Skip to content

Commit 92b5e20

Browse files
committed
Auto merge of #59008 - varkor:const-generics-infer, r=eddyb
Add const generics to infer (and transitive dependencies) Split out from #53645. This work is a collaborative effort with @yodaldevoid. There are a number of stubs. These are mainly to ensure we don't overlook them when completing the implementation, but are not necessary for the initial implementation. We plan to address these in follow up PRs. r? @eddyb / @nikomatsakis
2 parents 767f594 + a68ed06 commit 92b5e20

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1414
-213
lines changed

src/librustc/infer/canonical/canonicalizer.rs

+86-3
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ use crate::infer::canonical::{
1010
OriginalQueryValues,
1111
};
1212
use crate::infer::InferCtxt;
13+
use crate::mir::interpret::ConstValue;
1314
use std::sync::atomic::Ordering;
1415
use crate::ty::fold::{TypeFoldable, TypeFolder};
1516
use crate::ty::subst::Kind;
16-
use crate::ty::{self, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags};
17+
use crate::ty::{self, BoundVar, InferConst, Lift, List, Ty, TyCtxt, TypeFlags};
18+
use crate::ty::flags::FlagComputation;
1719

1820
use rustc_data_structures::fx::FxHashMap;
1921
use rustc_data_structures::indexed_vec::Idx;
@@ -432,6 +434,61 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
432434
}
433435
}
434436
}
437+
438+
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
439+
match ct.val {
440+
ConstValue::Infer(InferConst::Var(vid)) => {
441+
debug!("canonical: const var found with vid {:?}", vid);
442+
match self.infcx.unwrap().probe_const_var(vid) {
443+
Ok(c) => {
444+
debug!("(resolved to {:?})", c);
445+
return self.fold_const(c);
446+
}
447+
448+
// `ConstVar(vid)` is unresolved, track its universe index in the
449+
// canonicalized result
450+
Err(mut ui) => {
451+
if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk {
452+
// FIXME: perf problem described in #55921.
453+
ui = ty::UniverseIndex::ROOT;
454+
}
455+
return self.canonicalize_const_var(
456+
CanonicalVarInfo {
457+
kind: CanonicalVarKind::Const(ui),
458+
},
459+
ct,
460+
);
461+
}
462+
}
463+
}
464+
ConstValue::Infer(InferConst::Fresh(_)) => {
465+
bug!("encountered a fresh const during canonicalization")
466+
}
467+
ConstValue::Infer(InferConst::Canonical(debruijn, _)) => {
468+
if debruijn >= self.binder_index {
469+
bug!("escaping bound type during canonicalization")
470+
} else {
471+
return ct;
472+
}
473+
}
474+
ConstValue::Placeholder(placeholder) => {
475+
return self.canonicalize_const_var(
476+
CanonicalVarInfo {
477+
kind: CanonicalVarKind::PlaceholderConst(placeholder),
478+
},
479+
ct,
480+
);
481+
}
482+
_ => {}
483+
}
484+
485+
let flags = FlagComputation::for_const(ct);
486+
if flags.intersects(self.needs_canonical_flags) {
487+
ct.super_fold_with(self)
488+
} else {
489+
ct
490+
}
491+
}
435492
}
436493

437494
impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
@@ -450,11 +507,13 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
450507
let needs_canonical_flags = if canonicalize_region_mode.any() {
451508
TypeFlags::KEEP_IN_LOCAL_TCX |
452509
TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
453-
TypeFlags::HAS_TY_PLACEHOLDER
510+
TypeFlags::HAS_TY_PLACEHOLDER |
511+
TypeFlags::HAS_CT_PLACEHOLDER
454512
} else {
455513
TypeFlags::KEEP_IN_LOCAL_TCX |
456514
TypeFlags::HAS_RE_PLACEHOLDER |
457-
TypeFlags::HAS_TY_PLACEHOLDER
515+
TypeFlags::HAS_TY_PLACEHOLDER |
516+
TypeFlags::HAS_CT_PLACEHOLDER
458517
};
459518

460519
let gcx = tcx.global_tcx();
@@ -633,4 +692,28 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
633692
self.tcx().mk_ty(ty::Bound(self.binder_index, var.into()))
634693
}
635694
}
695+
696+
/// Given a type variable `const_var` of the given kind, first check
697+
/// if `const_var` is bound to anything; if so, canonicalize
698+
/// *that*. Otherwise, create a new canonical variable for
699+
/// `const_var`.
700+
fn canonicalize_const_var(
701+
&mut self,
702+
info: CanonicalVarInfo,
703+
const_var: &'tcx ty::Const<'tcx>
704+
) -> &'tcx ty::Const<'tcx> {
705+
let infcx = self.infcx.expect("encountered const-var without infcx");
706+
let bound_to = infcx.resolve_const_var(const_var);
707+
if bound_to != const_var {
708+
self.fold_const(bound_to)
709+
} else {
710+
let var = self.canonical_var(info, const_var.into());
711+
self.tcx().mk_const(
712+
ty::Const {
713+
val: ConstValue::Infer(InferConst::Canonical(self.binder_index, var.into())),
714+
ty: const_var.ty,
715+
}
716+
)
717+
}
718+
}
636719
}

src/librustc/infer/canonical/mod.rs

+47-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
//!
2222
//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html
2323
24-
use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin};
24+
use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, ConstVariableOrigin};
25+
use crate::mir::interpret::ConstValue;
2526
use rustc_data_structures::indexed_vec::IndexVec;
2627
use rustc_macros::HashStable;
2728
use serialize::UseSpecializedDecodable;
@@ -30,7 +31,7 @@ use std::ops::Index;
3031
use syntax::source_map::Span;
3132
use crate::ty::fold::TypeFoldable;
3233
use crate::ty::subst::Kind;
33-
use crate::ty::{self, BoundVar, Lift, List, Region, TyCtxt};
34+
use crate::ty::{self, BoundVar, InferConst, Lift, List, Region, TyCtxt};
3435

3536
mod canonicalizer;
3637

@@ -115,6 +116,8 @@ impl CanonicalVarInfo {
115116
CanonicalVarKind::PlaceholderTy(_) => false,
116117
CanonicalVarKind::Region(_) => true,
117118
CanonicalVarKind::PlaceholderRegion(..) => false,
119+
CanonicalVarKind::Const(_) => true,
120+
CanonicalVarKind::PlaceholderConst(_) => false,
118121
}
119122
}
120123
}
@@ -137,6 +140,12 @@ pub enum CanonicalVarKind {
137140
/// are solving a goal like `for<'a> T: Foo<'a>` to represent the
138141
/// bound region `'a`.
139142
PlaceholderRegion(ty::PlaceholderRegion),
143+
144+
/// Some kind of const inference variable.
145+
Const(ty::UniverseIndex),
146+
147+
/// A "placeholder" that represents "any const".
148+
PlaceholderConst(ty::PlaceholderConst),
140149
}
141150

142151
impl CanonicalVarKind {
@@ -150,6 +159,8 @@ impl CanonicalVarKind {
150159
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
151160
CanonicalVarKind::Region(ui) => ui,
152161
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
162+
CanonicalVarKind::Const(ui) => ui,
163+
CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
153164
}
154165
}
155166
}
@@ -388,6 +399,33 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
388399
};
389400
self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into()
390401
}
402+
403+
CanonicalVarKind::Const(ui) => {
404+
self.next_const_var_in_universe(
405+
self.next_ty_var_in_universe(
406+
TypeVariableOrigin::MiscVariable(span),
407+
universe_map(ui),
408+
),
409+
ConstVariableOrigin::MiscVariable(span),
410+
universe_map(ui),
411+
).into()
412+
}
413+
414+
CanonicalVarKind::PlaceholderConst(
415+
ty::PlaceholderConst { universe, name },
416+
) => {
417+
let universe_mapped = universe_map(universe);
418+
let placeholder_mapped = ty::PlaceholderConst {
419+
universe: universe_mapped,
420+
name,
421+
};
422+
self.tcx.mk_const(
423+
ty::Const {
424+
val: ConstValue::Placeholder(placeholder_mapped),
425+
ty: self.tcx.types.err, // FIXME(const_generics)
426+
}
427+
).into()
428+
}
391429
}
392430
}
393431
}
@@ -443,8 +481,13 @@ impl<'tcx> CanonicalVarValues<'tcx> {
443481
UnpackedKind::Lifetime(..) => tcx.mk_region(
444482
ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i))
445483
).into(),
446-
UnpackedKind::Const(..) => {
447-
unimplemented!() // FIXME(const_generics)
484+
UnpackedKind::Const(ct) => {
485+
tcx.mk_const(ty::Const {
486+
ty: ct.ty,
487+
val: ConstValue::Infer(
488+
InferConst::Canonical(ty::INNERMOST, ty::BoundVar::from_u32(i))
489+
),
490+
}).into()
448491
}
449492
})
450493
.collect()

src/librustc/infer/canonical/query_response.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::infer::canonical::{
1616
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
1717
use crate::infer::InferCtxtBuilder;
1818
use crate::infer::{InferCtxt, InferOk, InferResult};
19+
use crate::mir::interpret::ConstValue;
1920
use rustc_data_structures::indexed_vec::Idx;
2021
use rustc_data_structures::indexed_vec::IndexVec;
2122
use std::fmt::Debug;
@@ -25,7 +26,7 @@ use crate::traits::TraitEngine;
2526
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
2627
use crate::ty::fold::TypeFoldable;
2728
use crate::ty::subst::{Kind, UnpackedKind};
28-
use crate::ty::{self, BoundVar, Lift, Ty, TyCtxt};
29+
use crate::ty::{self, BoundVar, InferConst, Lift, Ty, TyCtxt};
2930
use crate::util::captures::Captures;
3031

3132
impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
@@ -479,8 +480,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
479480
opt_values[br.assert_bound_var()] = Some(*original_value);
480481
}
481482
}
482-
UnpackedKind::Const(..) => {
483-
unimplemented!() // FIXME(const_generics)
483+
UnpackedKind::Const(result_value) => {
484+
if let ty::Const {
485+
val: ConstValue::Infer(InferConst::Canonical(debrujin, b)),
486+
..
487+
} = result_value {
488+
// ...in which case we would set `canonical_vars[0]` to `Some(const X)`.
489+
490+
// We only allow a `ty::INNERMOST` index in substitutions.
491+
assert_eq!(*debrujin, ty::INNERMOST);
492+
opt_values[*b] = Some(*original_value);
493+
}
484494
}
485495
}
486496
}

src/librustc/infer/canonical/substitute.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,13 @@ where
7070
}
7171
};
7272

73-
tcx.replace_escaping_bound_vars(value, fld_r, fld_t).0
73+
let fld_c = |bound_ct: ty::BoundVar, _| {
74+
match var_values.var_values[bound_ct].unpack() {
75+
UnpackedKind::Const(ct) => ct,
76+
c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
77+
}
78+
};
79+
80+
tcx.replace_escaping_bound_vars(value, fld_r, fld_t, fld_c).0
7481
}
7582
}

0 commit comments

Comments
 (0)