Skip to content

Commit

Permalink
Auto merge of #59008 - varkor:const-generics-infer, r=eddyb
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed May 2, 2019
2 parents 767f594 + a68ed06 commit 92b5e20
Show file tree
Hide file tree
Showing 50 changed files with 1,414 additions and 213 deletions.
89 changes: 86 additions & 3 deletions src/librustc/infer/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ use crate::infer::canonical::{
OriginalQueryValues,
};
use crate::infer::InferCtxt;
use crate::mir::interpret::ConstValue;
use std::sync::atomic::Ordering;
use crate::ty::fold::{TypeFoldable, TypeFolder};
use crate::ty::subst::Kind;
use crate::ty::{self, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags};
use crate::ty::{self, BoundVar, InferConst, Lift, List, Ty, TyCtxt, TypeFlags};
use crate::ty::flags::FlagComputation;

use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
Expand Down Expand Up @@ -432,6 +434,61 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
}
}
}

fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
match ct.val {
ConstValue::Infer(InferConst::Var(vid)) => {
debug!("canonical: const var found with vid {:?}", vid);
match self.infcx.unwrap().probe_const_var(vid) {
Ok(c) => {
debug!("(resolved to {:?})", c);
return self.fold_const(c);
}

// `ConstVar(vid)` is unresolved, track its universe index in the
// canonicalized result
Err(mut ui) => {
if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk {
// FIXME: perf problem described in #55921.
ui = ty::UniverseIndex::ROOT;
}
return self.canonicalize_const_var(
CanonicalVarInfo {
kind: CanonicalVarKind::Const(ui),
},
ct,
);
}
}
}
ConstValue::Infer(InferConst::Fresh(_)) => {
bug!("encountered a fresh const during canonicalization")
}
ConstValue::Infer(InferConst::Canonical(debruijn, _)) => {
if debruijn >= self.binder_index {
bug!("escaping bound type during canonicalization")
} else {
return ct;
}
}
ConstValue::Placeholder(placeholder) => {
return self.canonicalize_const_var(
CanonicalVarInfo {
kind: CanonicalVarKind::PlaceholderConst(placeholder),
},
ct,
);
}
_ => {}
}

let flags = FlagComputation::for_const(ct);
if flags.intersects(self.needs_canonical_flags) {
ct.super_fold_with(self)
} else {
ct
}
}
}

impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
Expand All @@ -450,11 +507,13 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
let needs_canonical_flags = if canonicalize_region_mode.any() {
TypeFlags::KEEP_IN_LOCAL_TCX |
TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
TypeFlags::HAS_TY_PLACEHOLDER
TypeFlags::HAS_TY_PLACEHOLDER |
TypeFlags::HAS_CT_PLACEHOLDER
} else {
TypeFlags::KEEP_IN_LOCAL_TCX |
TypeFlags::HAS_RE_PLACEHOLDER |
TypeFlags::HAS_TY_PLACEHOLDER
TypeFlags::HAS_TY_PLACEHOLDER |
TypeFlags::HAS_CT_PLACEHOLDER
};

let gcx = tcx.global_tcx();
Expand Down Expand Up @@ -633,4 +692,28 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
self.tcx().mk_ty(ty::Bound(self.binder_index, var.into()))
}
}

/// Given a type variable `const_var` of the given kind, first check
/// if `const_var` is bound to anything; if so, canonicalize
/// *that*. Otherwise, create a new canonical variable for
/// `const_var`.
fn canonicalize_const_var(
&mut self,
info: CanonicalVarInfo,
const_var: &'tcx ty::Const<'tcx>
) -> &'tcx ty::Const<'tcx> {
let infcx = self.infcx.expect("encountered const-var without infcx");
let bound_to = infcx.resolve_const_var(const_var);
if bound_to != const_var {
self.fold_const(bound_to)
} else {
let var = self.canonical_var(info, const_var.into());
self.tcx().mk_const(
ty::Const {
val: ConstValue::Infer(InferConst::Canonical(self.binder_index, var.into())),
ty: const_var.ty,
}
)
}
}
}
51 changes: 47 additions & 4 deletions src/librustc/infer/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
//!
//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html

use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin};
use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, ConstVariableOrigin};
use crate::mir::interpret::ConstValue;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_macros::HashStable;
use serialize::UseSpecializedDecodable;
Expand All @@ -30,7 +31,7 @@ use std::ops::Index;
use syntax::source_map::Span;
use crate::ty::fold::TypeFoldable;
use crate::ty::subst::Kind;
use crate::ty::{self, BoundVar, Lift, List, Region, TyCtxt};
use crate::ty::{self, BoundVar, InferConst, Lift, List, Region, TyCtxt};

mod canonicalizer;

Expand Down Expand Up @@ -115,6 +116,8 @@ impl CanonicalVarInfo {
CanonicalVarKind::PlaceholderTy(_) => false,
CanonicalVarKind::Region(_) => true,
CanonicalVarKind::PlaceholderRegion(..) => false,
CanonicalVarKind::Const(_) => true,
CanonicalVarKind::PlaceholderConst(_) => false,
}
}
}
Expand All @@ -137,6 +140,12 @@ pub enum CanonicalVarKind {
/// are solving a goal like `for<'a> T: Foo<'a>` to represent the
/// bound region `'a`.
PlaceholderRegion(ty::PlaceholderRegion),

/// Some kind of const inference variable.
Const(ty::UniverseIndex),

/// A "placeholder" that represents "any const".
PlaceholderConst(ty::PlaceholderConst),
}

impl CanonicalVarKind {
Expand All @@ -150,6 +159,8 @@ impl CanonicalVarKind {
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
CanonicalVarKind::Region(ui) => ui,
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
CanonicalVarKind::Const(ui) => ui,
CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
}
}
}
Expand Down Expand Up @@ -388,6 +399,33 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
};
self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into()
}

CanonicalVarKind::Const(ui) => {
self.next_const_var_in_universe(
self.next_ty_var_in_universe(
TypeVariableOrigin::MiscVariable(span),
universe_map(ui),
),
ConstVariableOrigin::MiscVariable(span),
universe_map(ui),
).into()
}

CanonicalVarKind::PlaceholderConst(
ty::PlaceholderConst { universe, name },
) => {
let universe_mapped = universe_map(universe);
let placeholder_mapped = ty::PlaceholderConst {
universe: universe_mapped,
name,
};
self.tcx.mk_const(
ty::Const {
val: ConstValue::Placeholder(placeholder_mapped),
ty: self.tcx.types.err, // FIXME(const_generics)
}
).into()
}
}
}
}
Expand Down Expand Up @@ -443,8 +481,13 @@ impl<'tcx> CanonicalVarValues<'tcx> {
UnpackedKind::Lifetime(..) => tcx.mk_region(
ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i))
).into(),
UnpackedKind::Const(..) => {
unimplemented!() // FIXME(const_generics)
UnpackedKind::Const(ct) => {
tcx.mk_const(ty::Const {
ty: ct.ty,
val: ConstValue::Infer(
InferConst::Canonical(ty::INNERMOST, ty::BoundVar::from_u32(i))
),
}).into()
}
})
.collect()
Expand Down
16 changes: 13 additions & 3 deletions src/librustc/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::infer::canonical::{
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::InferCtxtBuilder;
use crate::infer::{InferCtxt, InferOk, InferResult};
use crate::mir::interpret::ConstValue;
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::indexed_vec::IndexVec;
use std::fmt::Debug;
Expand All @@ -25,7 +26,7 @@ use crate::traits::TraitEngine;
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
use crate::ty::fold::TypeFoldable;
use crate::ty::subst::{Kind, UnpackedKind};
use crate::ty::{self, BoundVar, Lift, Ty, TyCtxt};
use crate::ty::{self, BoundVar, InferConst, Lift, Ty, TyCtxt};
use crate::util::captures::Captures;

impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
Expand Down Expand Up @@ -479,8 +480,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
opt_values[br.assert_bound_var()] = Some(*original_value);
}
}
UnpackedKind::Const(..) => {
unimplemented!() // FIXME(const_generics)
UnpackedKind::Const(result_value) => {
if let ty::Const {
val: ConstValue::Infer(InferConst::Canonical(debrujin, b)),
..
} = result_value {
// ...in which case we would set `canonical_vars[0]` to `Some(const X)`.

// We only allow a `ty::INNERMOST` index in substitutions.
assert_eq!(*debrujin, ty::INNERMOST);
opt_values[*b] = Some(*original_value);
}
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/librustc/infer/canonical/substitute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ where
}
};

tcx.replace_escaping_bound_vars(value, fld_r, fld_t).0
let fld_c = |bound_ct: ty::BoundVar, _| {
match var_values.var_values[bound_ct].unpack() {
UnpackedKind::Const(ct) => ct,
c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
}
};

tcx.replace_escaping_bound_vars(value, fld_r, fld_t, fld_c).0
}
}
Loading

0 comments on commit 92b5e20

Please sign in to comment.