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
This commit is contained in:
bors 2019-05-02 04:47:36 +00:00
commit 92b5e20ad5
50 changed files with 1414 additions and 213 deletions

View File

@ -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;
@ -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> {
@ -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();
@ -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,
}
)
}
}
}

View File

@ -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;
@ -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;
@ -115,6 +116,8 @@ impl CanonicalVarInfo {
CanonicalVarKind::PlaceholderTy(_) => false,
CanonicalVarKind::Region(_) => true,
CanonicalVarKind::PlaceholderRegion(..) => false,
CanonicalVarKind::Const(_) => true,
CanonicalVarKind::PlaceholderConst(_) => false,
}
}
}
@ -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 {
@ -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,
}
}
}
@ -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()
}
}
}
}
@ -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()

View File

@ -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;
@ -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> {
@ -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);
}
}
}
}

View File

@ -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
}
}

View File

@ -28,17 +28,19 @@ use super::{InferCtxt, MiscVariable, TypeTrace};
use super::lub::Lub;
use super::sub::Sub;
use super::type_variable::TypeVariableValue;
use super::unify_key::{ConstVarValue, ConstVariableValue, ConstVariableOrigin};
use crate::hir::def_id::DefId;
use crate::mir::interpret::ConstValue;
use crate::ty::{IntType, UintType};
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{self, Ty, TyCtxt, InferConst};
use crate::ty::error::TypeError;
use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
use crate::ty::subst::SubstsRef;
use crate::traits::{Obligation, PredicateObligations};
use syntax::ast;
use syntax_pos::Span;
use syntax_pos::{Span, DUMMY_SP};
#[derive(Clone)]
pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
@ -107,13 +109,69 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> {
Err(TypeError::Sorts(ty::relate::expected_found(relation, &a, &b)))
}
_ => {
ty::relate::super_relate_tys(relation, a, b)
}
}
}
pub fn super_combine_consts<R>(
&self,
relation: &mut R,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>
where
R: TypeRelation<'infcx, 'gcx, 'tcx>,
{
let a_is_expected = relation.a_is_expected();
match (a.val, b.val) {
(ConstValue::Infer(InferConst::Var(a_vid)),
ConstValue::Infer(InferConst::Var(b_vid))) => {
self.const_unification_table
.borrow_mut()
.unify_var_var(a_vid, b_vid)
.map_err(|e| const_unification_error(a_is_expected, e))?;
return Ok(a);
}
// All other cases of inference with other variables are errors.
(ConstValue::Infer(InferConst::Var(_)), ConstValue::Infer(_)) |
(ConstValue::Infer(_), ConstValue::Infer(InferConst::Var(_))) => {
bug!("tried to combine ConstValue::Infer/ConstValue::Infer(InferConst::Var)")
}
(ConstValue::Infer(InferConst::Var(vid)), _) => {
return self.unify_const_variable(a_is_expected, vid, b);
}
(_, ConstValue::Infer(InferConst::Var(vid))) => {
return self.unify_const_variable(!a_is_expected, vid, a);
}
_ => {}
}
ty::relate::super_relate_consts(relation, a, b)
}
pub fn unify_const_variable(
&self,
vid_is_expected: bool,
vid: ty::ConstVid<'tcx>,
value: &'tcx ty::Const<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
self.const_unification_table
.borrow_mut()
.unify_var_value(vid, ConstVarValue {
origin: ConstVariableOrigin::ConstInference(DUMMY_SP),
val: ConstVariableValue::Known { value },
})
.map_err(|e| const_unification_error(vid_is_expected, e))?;
Ok(value)
}
fn unify_integral_variable(&self,
vid_is_expected: bool,
vid: ty::IntVid,
@ -407,7 +465,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
debug!("generalize: t={:?}", t);
// Check to see whether the type we are genealizing references
// Check to see whether the type we are generalizing references
// any other type variable related to `vid` via
// subtyping. This is basically our "occurs check", preventing
// us from creating infinitely sized types.
@ -519,6 +577,29 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
// very descriptive origin for this region variable.
Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe))
}
fn consts(
&mut self,
c: &'tcx ty::Const<'tcx>,
c2: &'tcx ty::Const<'tcx>
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
match c {
ty::Const { val: ConstValue::Infer(InferConst::Var(vid)), .. } => {
let mut variable_table = self.infcx.const_unification_table.borrow_mut();
match variable_table.probe_value(*vid).val.known() {
Some(u) => {
self.relate(&u, &u)
}
None => Ok(c),
}
}
_ => {
relate::super_relate_consts(self, c, c)
}
}
}
}
pub trait RelateResultCompare<'tcx, T> {
@ -540,6 +621,13 @@ impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'t
}
}
pub fn const_unification_error<'tcx>(
a_is_expected: bool,
(a, b): (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>),
) -> TypeError<'tcx> {
TypeError::ConstMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b))
}
fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue))
-> TypeError<'tcx>
{

View File

@ -1,12 +1,14 @@
use super::combine::{CombineFields, RelationDir};
use super::{Subtype};
use super::combine::{CombineFields, RelationDir, const_unification_error};
use super::Subtype;
use crate::hir::def_id::DefId;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{self, Ty, TyCtxt, InferConst};
use crate::ty::TyVar;
use crate::ty::subst::SubstsRef;
use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
use crate::mir::interpret::ConstValue;
use crate::infer::unify_key::replace_if_possible;
/// Ensures `a` is made equal to `b`. Returns `a` on success.
pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
@ -100,6 +102,46 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
Ok(a)
}
fn consts(
&mut self,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
if a == b { return Ok(a); }
let infcx = self.fields.infcx;
let a = replace_if_possible(infcx.const_unification_table.borrow_mut(), a);
let b = replace_if_possible(infcx.const_unification_table.borrow_mut(), b);
let a_is_expected = self.a_is_expected();
match (a.val, b.val) {
(ConstValue::Infer(InferConst::Var(a_vid)),
ConstValue::Infer(InferConst::Var(b_vid))) => {
infcx.const_unification_table
.borrow_mut()
.unify_var_var(a_vid, b_vid)
.map_err(|e| const_unification_error(a_is_expected, e))?;
return Ok(a);
}
(ConstValue::Infer(InferConst::Var(a_id)), _) => {
self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?;
return Ok(a);
}
(_, ConstValue::Infer(InferConst::Var(b_id))) => {
self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?;
return Ok(a);
}
_ => {}
}
self.fields.infcx.super_combine_consts(self, a, b)?;
Ok(a)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>

View File

@ -31,6 +31,7 @@
//! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type
//! inferencer knows "so far".
use crate::mir::interpret::ConstValue;
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
use crate::ty::fold::TypeFolder;
use crate::util::nodemap::FxHashMap;
@ -42,8 +43,10 @@ use super::unify_key::ToType;
pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
freshen_count: u32,
freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
ty_freshen_count: u32,
const_freshen_count: u32,
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
const_freshen_map: FxHashMap<ty::InferConst<'tcx>, &'tcx ty::Const<'tcx>>,
}
impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
@ -51,33 +54,63 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> {
-> TypeFreshener<'a, 'gcx, 'tcx> {
TypeFreshener {
infcx,
freshen_count: 0,
freshen_map: Default::default(),
ty_freshen_count: 0,
const_freshen_count: 0,
ty_freshen_map: Default::default(),
const_freshen_map: Default::default(),
}
}
fn freshen<F>(&mut self,
opt_ty: Option<Ty<'tcx>>,
key: ty::InferTy,
freshener: F)
-> Ty<'tcx> where
fn freshen_ty<F>(
&mut self,
opt_ty: Option<Ty<'tcx>>,
key: ty::InferTy,
freshener: F,
) -> Ty<'tcx>
where
F: FnOnce(u32) -> ty::InferTy,
{
if let Some(ty) = opt_ty {
return ty.fold_with(self);
}
match self.freshen_map.entry(key) {
match self.ty_freshen_map.entry(key) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let index = self.freshen_count;
self.freshen_count += 1;
let t = self.infcx.tcx.mk_infer(freshener(index));
let index = self.ty_freshen_count;
self.ty_freshen_count += 1;
let t = self.infcx.tcx.mk_ty_infer(freshener(index));
entry.insert(t);
t
}
}
}
fn freshen_const<F>(
&mut self,
opt_ct: Option<&'tcx ty::Const<'tcx>>,
key: ty::InferConst<'tcx>,
freshener: F,
ty: Ty<'tcx>,
) -> &'tcx ty::Const<'tcx>
where
F: FnOnce(u32) -> ty::InferConst<'tcx>,
{
if let Some(ct) = opt_ct {
return ct.fold_with(self);
}
match self.const_freshen_map.entry(key) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let index = self.const_freshen_count;
self.const_freshen_count += 1;
let ct = self.infcx.tcx.mk_const_infer(freshener(index), ty);
entry.insert(ct);
ct
}
}
}
}
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
@ -124,14 +157,14 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
match t.sty {
ty::Infer(ty::TyVar(v)) => {
let opt_ty = self.infcx.type_variables.borrow_mut().probe(v).known();
self.freshen(
self.freshen_ty(
opt_ty,
ty::TyVar(v),
ty::FreshTy)
}
ty::Infer(ty::IntVar(v)) => {
self.freshen(
self.freshen_ty(
self.infcx.int_unification_table.borrow_mut()
.probe_value(v)
.map(|v| v.to_type(tcx)),
@ -140,7 +173,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
}
ty::Infer(ty::FloatVar(v)) => {
self.freshen(
self.freshen_ty(
self.infcx.float_unification_table.borrow_mut()
.probe_value(v)
.map(|v| v.to_type(tcx)),
@ -148,14 +181,14 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
ty::FreshFloatTy)
}
ty::Infer(ty::FreshTy(c)) |
ty::Infer(ty::FreshIntTy(c)) |
ty::Infer(ty::FreshFloatTy(c)) => {
if c >= self.freshen_count {
ty::Infer(ty::FreshTy(ct)) |
ty::Infer(ty::FreshIntTy(ct)) |
ty::Infer(ty::FreshFloatTy(ct)) => {
if ct >= self.ty_freshen_count {
bug!("Encountered a freshend type with id {} \
but our counter is only at {}",
c,
self.freshen_count);
ct,
self.ty_freshen_count);
}
t
}
@ -192,4 +225,46 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
ty::Bound(..) => bug!("unexpected type {:?}", t),
}
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
match ct.val {
ConstValue::Infer(ty::InferConst::Var(v)) => {
let opt_ct = self.infcx.const_unification_table
.borrow_mut()
.probe_value(v)
.val
.known();
return self.freshen_const(
opt_ct,
ty::InferConst::Var(v),
ty::InferConst::Fresh,
ct.ty,
);
}
ConstValue::Infer(ty::InferConst::Fresh(i)) => {
if i >= self.const_freshen_count {
bug!(
"Encountered a freshend const with id {} \
but our counter is only at {}",
i,
self.const_freshen_count,
);
}
return ct;
}
ConstValue::Infer(ty::InferConst::Canonical(..)) |
ConstValue::Placeholder(_) => {
bug!("unexpected const {:?}", ct)
}
ConstValue::Param(_) |
ConstValue::Scalar(_) |
ConstValue::Slice(..) |
ConstValue::ByRef(..) |
ConstValue::Unevaluated(..) => {}
}
ct.super_fold_with(self)
}
}

View File

@ -1,12 +1,27 @@
use crate::ty::{self, Ty, TyCtxt, TyVid, IntVid, FloatVid, RegionVid};
use crate::ty::{self, Ty, TyCtxt, TyVid, IntVid, FloatVid, RegionVid, ConstVid};
use crate::ty::fold::{TypeFoldable, TypeFolder};
use crate::mir::interpret::ConstValue;
use super::InferCtxt;
use super::RegionVariableOrigin;
use super::{RegionVariableOrigin, ConstVariableOrigin};
use super::type_variable::TypeVariableOrigin;
use rustc_data_structures::unify as ut;
use ut::UnifyKey;
use std::cell::RefMut;
use std::ops::Range;
fn const_vars_since_snapshot<'tcx>(
mut table: RefMut<'_, ut::UnificationTable<ut::InPlace<ConstVid<'tcx>>>>,
snapshot: &ut::Snapshot<ut::InPlace<ConstVid<'tcx>>>,
) -> (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>) {
let range = table.vars_since_snapshot(snapshot);
(range.start..range.end, (range.start.index..range.end.index).map(|index| {
table.probe_value(ConstVid::from_index(index)).origin.clone()
}).collect())
}
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// This rather funky routine is used while processing expected
/// types. What happens here is that we want to propagate a
@ -79,6 +94,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let region_vars = self.borrow_region_constraints().vars_since_snapshot(
&snapshot.region_constraints_snapshot,
);
let const_vars = const_vars_since_snapshot(
self.const_unification_table.borrow_mut(),
&snapshot.const_snapshot,
);
let fudger = InferenceFudger {
infcx: self,
@ -86,6 +105,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
int_vars,
float_vars,
region_vars,
const_vars,
};
Ok((fudger, value))
@ -104,7 +124,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
if fudger.type_vars.0.is_empty() &&
fudger.int_vars.is_empty() &&
fudger.float_vars.is_empty() &&
fudger.region_vars.0.is_empty() {
fudger.region_vars.0.is_empty() &&
fudger.const_vars.0.is_empty() {
Ok(value)
} else {
Ok(value.fold_with(&mut fudger))
@ -118,6 +139,7 @@ pub struct InferenceFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
int_vars: Range<IntVid>,
float_vars: Range<FloatVid>,
region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>),
const_vars: (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>),
}
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for InferenceFudger<'a, 'gcx, 'tcx> {
@ -165,13 +187,29 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for InferenceFudger<'a, 'gcx, 'tcx>
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
if let ty::ReVar(vid) = r {
if let ty::ReVar(vid) = *r {
if self.region_vars.0.contains(&vid) {
let idx = (vid.index() - self.region_vars.0.start.index()) as usize;
let idx = vid.index() - self.region_vars.0.start.index();
let origin = self.region_vars.1[idx];
return self.infcx.next_region_var(origin);
}
}
r
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if let ty::Const { val: ConstValue::Infer(ty::InferConst::Var(vid)), ty } = ct {
if self.const_vars.0.contains(&vid) {
// This variable was created during the fudging.
// Recreate it with a fresh variable here.
let idx = (vid.index - self.const_vars.0.start.index) as usize;
let origin = self.const_vars.1[idx];
self.infcx.next_const_var(ty, origin)
} else {
ct
}
} else {
ct.super_fold_with(self)
}
}
}

View File

@ -60,6 +60,19 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
Ok(self.fields.infcx.borrow_region_constraints().glb_regions(self.tcx(), origin, a, b))
}
fn consts(
&mut self,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
if a == b {
return Ok(a);
}
self.fields.infcx.super_combine_consts(self, a, b)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>

View File

@ -7,6 +7,7 @@ use super::{HigherRankedType, InferCtxt, PlaceholderMap};
use crate::infer::CombinedSnapshot;
use crate::ty::relate::{Relate, RelateResult, TypeRelation};
use crate::ty::{self, Binder, TypeFoldable};
use crate::mir::interpret::ConstValue;
impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
pub fn higher_ranked_sub<T>(
@ -99,7 +100,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}))
};
let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t);
let fld_c = |bound_var: ty::BoundVar, ty| {
self.tcx.mk_const(
ty::Const {
val: ConstValue::Placeholder(ty::PlaceholderConst {
universe: next_universe,
name: bound_var,
}),
ty,
}
)
};
let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c);
debug!(
"replace_bound_vars_with_placeholders(\

View File

@ -60,6 +60,19 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
Ok(self.fields.infcx.borrow_region_constraints().lub_regions(self.tcx(), origin, a, b))
}
fn consts(
&mut self,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
if a == b {
return Ok(a);
}
self.fields.infcx.super_combine_consts(self, a, b)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>

View File

@ -10,17 +10,19 @@ pub use crate::ty::IntVarValue;
use crate::hir;
use crate::hir::def_id::DefId;
use crate::infer::canonical::{Canonical, CanonicalVarValues};
use crate::infer::unify_key::{ConstVarValue, ConstVariableValue};
use crate::middle::free_region::RegionRelations;
use crate::middle::lang_items;
use crate::middle::region;
use crate::mir::interpret::ConstValue;
use crate::session::config::BorrowckMode;
use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
use crate::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use crate::ty::fold::TypeFoldable;
use crate::ty::fold::{TypeFolder, TypeFoldable};
use crate::ty::relate::RelateResult;
use crate::ty::subst::{Kind, InternalSubsts, SubstsRef};
use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt, CtxtInterners};
use crate::ty::{FloatVid, IntVid, TyVid};
use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt, CtxtInterners, InferConst};
use crate::ty::{FloatVid, IntVid, TyVid, ConstVid};
use crate::util::nodemap::FxHashMap;
use arena::SyncDroplessArena;
@ -39,7 +41,7 @@ use self::outlives::env::OutlivesEnvironment;
use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
use self::type_variable::TypeVariableOrigin;
use self::unify_key::ToType;
use self::unify_key::{ToType, ConstVariableOrigin};
pub mod at;
pub mod canonical;
@ -72,7 +74,7 @@ pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;
pub type Bound<T> = Option<T>;
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result"
/// A flag that is used to suppress region errors. This is normally
/// false, but sometimes -- when we are doing region checks that the
@ -122,7 +124,10 @@ pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
/// order, represented by its upper and lower bounds.
pub type_variables: RefCell<type_variable::TypeVariableTable<'tcx>>,
/// Map from integral variable to the kind of integer it represents
/// Map from const parameter variable to the kind of const it represents.
const_unification_table: RefCell<ut::UnificationTable<ut::InPlace<ty::ConstVid<'tcx>>>>,
/// Map from integral variable to the kind of integer it represents.
int_unification_table: RefCell<ut::UnificationTable<ut::InPlace<ty::IntVid>>>,
/// Map from floating variable to the kind of float it represents
@ -422,10 +427,11 @@ impl NLLRegionVariableOrigin {
}
#[derive(Copy, Clone, Debug)]
pub enum FixupError {
pub enum FixupError<'tcx> {
UnresolvedIntTy(IntVid),
UnresolvedFloatTy(FloatVid),
UnresolvedTy(TyVid),
UnresolvedConst(ConstVid<'tcx>),
}
/// See the `region_obligations` field for more information.
@ -436,7 +442,7 @@ pub struct RegionObligation<'tcx> {
pub origin: SubregionOrigin<'tcx>,
}
impl fmt::Display for FixupError {
impl<'tcx> fmt::Display for FixupError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::FixupError::*;
@ -452,6 +458,7 @@ impl fmt::Display for FixupError {
add a suffix to specify the type explicitly"
),
UnresolvedTy(_) => write!(f, "unconstrained type"),
UnresolvedConst(_) => write!(f, "unconstrained const value"),
}
}
}
@ -524,6 +531,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
in_progress_tables,
projection_cache: Default::default(),
type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
const_unification_table: RefCell::new(ut::UnificationTable::new()),
int_unification_table: RefCell::new(ut::UnificationTable::new()),
float_unification_table: RefCell::new(ut::UnificationTable::new()),
region_constraints: RefCell::new(Some(RegionConstraintCollector::new())),
@ -589,6 +597,7 @@ impl<'tcx> InferOk<'tcx, ()> {
pub struct CombinedSnapshot<'a, 'tcx: 'a> {
projection_cache_snapshot: traits::ProjectionCacheSnapshot,
type_snapshot: type_variable::Snapshot<'tcx>,
const_snapshot: ut::Snapshot<ut::InPlace<ty::ConstVid<'tcx>>>,
int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>,
float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>,
region_constraints_snapshot: RegionSnapshot,
@ -652,6 +661,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let mut type_variables = self.type_variables.borrow_mut();
let mut int_unification_table = self.int_unification_table.borrow_mut();
let mut float_unification_table = self.float_unification_table.borrow_mut();
// FIXME(const_generics): should there be an equivalent function for const variables?
type_variables
.unsolved_variables()
@ -722,6 +732,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
CombinedSnapshot {
projection_cache_snapshot: self.projection_cache.borrow_mut().snapshot(),
type_snapshot: self.type_variables.borrow_mut().snapshot(),
const_snapshot: self.const_unification_table.borrow_mut().snapshot(),
int_snapshot: self.int_unification_table.borrow_mut().snapshot(),
float_snapshot: self.float_unification_table.borrow_mut().snapshot(),
region_constraints_snapshot: self.borrow_region_constraints().start_snapshot(),
@ -739,6 +750,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let CombinedSnapshot {
projection_cache_snapshot,
type_snapshot,
const_snapshot,
int_snapshot,
float_snapshot,
region_constraints_snapshot,
@ -751,21 +763,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.in_snapshot.set(was_in_snapshot);
self.universe.set(universe);
self.projection_cache
.borrow_mut()
.rollback_to(projection_cache_snapshot);
self.projection_cache.borrow_mut().rollback_to(projection_cache_snapshot);
self.type_variables.borrow_mut().rollback_to(type_snapshot);
self.int_unification_table
.borrow_mut()
.rollback_to(int_snapshot);
self.float_unification_table
.borrow_mut()
.rollback_to(float_snapshot);
self.region_obligations
.borrow_mut()
.truncate(region_obligations_snapshot);
self.borrow_region_constraints()
.rollback_to(region_constraints_snapshot);
self.const_unification_table.borrow_mut().rollback_to(const_snapshot);
self.int_unification_table.borrow_mut().rollback_to(int_snapshot);
self.float_unification_table.borrow_mut().rollback_to(float_snapshot);
self.region_obligations.borrow_mut().truncate(region_obligations_snapshot);
self.borrow_region_constraints().rollback_to(region_constraints_snapshot);
}
fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
@ -773,6 +777,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let CombinedSnapshot {
projection_cache_snapshot,
type_snapshot,
const_snapshot,
int_snapshot,
float_snapshot,
region_constraints_snapshot,
@ -784,16 +789,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.in_snapshot.set(was_in_snapshot);
self.projection_cache
.borrow_mut()
.commit(projection_cache_snapshot);
self.projection_cache.borrow_mut().commit(projection_cache_snapshot);
self.type_variables.borrow_mut().commit(type_snapshot);
self.const_unification_table.borrow_mut().commit(const_snapshot);
self.int_unification_table.borrow_mut().commit(int_snapshot);
self.float_unification_table
.borrow_mut()
.commit(float_snapshot);
self.borrow_region_constraints()
.commit(region_constraints_snapshot);
self.float_unification_table.borrow_mut().commit(float_snapshot);
self.borrow_region_constraints().commit(region_constraints_snapshot);
}
/// Executes `f` and commit the bindings.
@ -999,6 +1000,38 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.tcx.mk_ty_var(self.next_ty_var_id(true, origin))
}
pub fn next_const_var(
&self,
ty: Ty<'tcx>,
origin: ConstVariableOrigin
) -> &'tcx ty::Const<'tcx> {
self.tcx.mk_const_var(self.next_const_var_id(origin), ty)
}
pub fn next_const_var_in_universe(
&self,
ty: Ty<'tcx>,
origin: ConstVariableOrigin,
universe: ty::UniverseIndex,
) -> &'tcx ty::Const<'tcx> {
let vid = self.const_unification_table
.borrow_mut()
.new_key(ConstVarValue {
origin,
val: ConstVariableValue::Unknown { universe },
});
self.tcx.mk_const_var(vid, ty)
}
pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> {
self.const_unification_table
.borrow_mut()
.new_key(ConstVarValue {
origin,
val: ConstVariableValue::Unknown { universe: self.universe() },
})
}
fn next_int_var_id(&self) -> IntVid {
self.int_unification_table.borrow_mut().new_key(None)
}
@ -1092,7 +1125,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.tcx.mk_ty_var(ty_var_id).into()
}
GenericParamDefKind::Const { .. } => {
unimplemented!() // FIXME(const_generics)
let origin = ConstVariableOrigin::ConstParameterDefinition(span, param.name);
let const_var_id =
self.const_unification_table
.borrow_mut()
.new_key(ConstVarValue {
origin,
val: ConstVariableValue::Unknown { universe: self.universe() },
});
self.tcx.mk_const_var(const_var_id, self.tcx.type_of(param.def_id)).into()
}
}
}
@ -1233,46 +1274,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.resolve_type_vars_if_possible(t).to_string()
}
// We have this force-inlined variant of shallow_resolve() for the one
// callsite that is extremely hot. All other callsites use the normal
// variant.
#[inline(always)]
pub fn inlined_shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
match typ.sty {
ty::Infer(ty::TyVar(v)) => {
// Not entirely obvious: if `typ` is a type variable,
// it can be resolved to an int/float variable, which
// can then be recursively resolved, hence the
// recursion. Note though that we prevent type
// variables from unifyxing to other type variables
// directly (though they may be embedded
// structurally), and we prevent cycles in any case,
// so this recursion should always be of very limited
// depth.
self.type_variables
.borrow_mut()
.probe(v)
.known()
.map(|t| self.shallow_resolve(t))
.unwrap_or(typ)
}
ty::Infer(ty::IntVar(v)) => self.int_unification_table
.borrow_mut()
.probe_value(v)
.map(|v| v.to_type(self.tcx))
.unwrap_or(typ),
ty::Infer(ty::FloatVar(v)) => self.float_unification_table
.borrow_mut()
.probe_value(v)
.map(|v| v.to_type(self.tcx))
.unwrap_or(typ),
_ => typ,
}
}
/// If `TyVar(vid)` resolves to a type, return that type. Else, return the
/// universe index of `TyVar(vid)`.
pub fn probe_ty_var(&self, vid: TyVid) -> Result<Ty<'tcx>, ty::UniverseIndex> {
@ -1284,8 +1285,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}
pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
self.inlined_shallow_resolve(typ)
pub fn shallow_resolve<T>(&self, value: T) -> T
where
T: TypeFoldable<'tcx>,
{
let mut r = ShallowResolver::new(self);
value.fold_with(&mut r)
}
pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
@ -1323,9 +1328,36 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
r.first_unresolved
}
pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<T> {
pub fn probe_const_var(
&self,
vid: ty::ConstVid<'tcx>
) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> {
match self.const_unification_table.borrow_mut().probe_value(vid).val {
ConstVariableValue::Known { value } => Ok(value),
ConstVariableValue::Unknown { universe } => Err(universe),
}
}
pub fn resolve_const_var(
&self,
ct: &'tcx ty::Const<'tcx>
) -> &'tcx ty::Const<'tcx> {
if let ty::Const { val: ConstValue::Infer(InferConst::Var(v)), .. } = ct {
self.const_unification_table
.borrow_mut()
.probe_value(*v)
.val
.known()
.map(|c| self.resolve_const_var(c))
.unwrap_or(ct)
} else {
ct
}
}
pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<'tcx, T> {
/*!
* Attempts to resolve all type/region variables in
* Attempts to resolve all type/region/const variables in
* `value`. Region inference must have been run already (e.g.,
* by calling `resolve_regions_and_report_errors`). If some
* variable was never unified, an `Err` results.
@ -1390,7 +1422,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
{
let fld_r = |br| self.next_region_var(LateBoundRegion(span, br, lbrct));
let fld_t = |_| self.next_ty_var(TypeVariableOrigin::MiscVariable(span));
self.tcx.replace_bound_vars(value, fld_r, fld_t)
let fld_c = |_, ty| self.next_const_var(ty, ConstVariableOrigin::MiscVariable(span));
self.tcx.replace_bound_vars(value, fld_r, fld_t, fld_c)
}
/// See the [`region_constraints::verify_generic_bound`] method.
@ -1441,7 +1474,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
closure_substs: ty::ClosureSubsts<'tcx>,
) -> Option<ty::ClosureKind> {
let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self.tcx);
let closure_kind_ty = self.shallow_resolve(&closure_kind_ty);
let closure_kind_ty = self.shallow_resolve(closure_kind_ty);
closure_kind_ty.to_opt_closure_kind()
}
@ -1455,7 +1488,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
substs: ty::ClosureSubsts<'tcx>,
) -> ty::PolyFnSig<'tcx> {
let closure_sig_ty = substs.closure_sig_ty(def_id, self.tcx);
let closure_sig_ty = self.shallow_resolve(&closure_sig_ty);
let closure_sig_ty = self.shallow_resolve(closure_sig_ty);
closure_sig_ty.fn_sig(self.tcx)
}
@ -1511,6 +1544,82 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}
pub struct ShallowResolver<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
}
impl<'a, 'gcx, 'tcx> ShallowResolver<'a, 'gcx, 'tcx> {
#[inline(always)]
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self {
ShallowResolver { infcx }
}
// We have this force-inlined variant of `shallow_resolve` for the one
// callsite that is extremely hot. All other callsites use the normal
// variant.
#[inline(always)]
pub fn inlined_shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> {
match typ.sty {
ty::Infer(ty::TyVar(v)) => {
// Not entirely obvious: if `typ` is a type variable,
// it can be resolved to an int/float variable, which
// can then be recursively resolved, hence the
// recursion. Note though that we prevent type
// variables from unifyxing to other type variables
// directly (though they may be embedded
// structurally), and we prevent cycles in any case,
// so this recursion should always be of very limited
// depth.
self.infcx.type_variables
.borrow_mut()
.probe(v)
.known()
.map(|t| self.fold_ty(t))
.unwrap_or(typ)
}
ty::Infer(ty::IntVar(v)) => self.infcx.int_unification_table
.borrow_mut()
.probe_value(v)
.map(|v| v.to_type(self.infcx.tcx))
.unwrap_or(typ),
ty::Infer(ty::FloatVar(v)) => self.infcx.float_unification_table
.borrow_mut()
.probe_value(v)
.map(|v| v.to_type(self.infcx.tcx))
.unwrap_or(typ),
_ => typ,
}
}
}
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ShallowResolver<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
self.inlined_shallow_resolve(ty)
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
match ct {
ty::Const { val: ConstValue::Infer(InferConst::Var(vid)), .. } => {
self.infcx.const_unification_table
.borrow_mut()
.probe_value(*vid)
.val
.known()
.map(|c| self.fold_const(c))
.unwrap_or(ct)
}
_ => ct,
}
}
}
impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> {
pub fn span(&self) -> Span {
self.cause.span

View File

@ -27,7 +27,8 @@ use crate::ty::error::TypeError;
use crate::ty::fold::{TypeFoldable, TypeVisitor};
use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
use crate::ty::subst::Kind;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{self, Ty, TyCtxt, InferConst};
use crate::mir::interpret::ConstValue;
use rustc_data_structures::fx::FxHashMap;
use std::fmt::Debug;
@ -608,6 +609,21 @@ where
Ok(a)
}
fn consts(
&mut self,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
if let ty::Const { val: ConstValue::Infer(InferConst::Canonical(_, _)), .. } = a {
// FIXME(const_generics): I'm unsure how this branch should actually be handled,
// so this is probably not correct.
self.infcx.super_combine_consts(self, a, b)
} else {
debug!("consts(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance);
relate::super_relate_consts(self, a, b)
}
}
fn binders<T>(
&mut self,
a: &ty::Binder<T>,
@ -853,7 +869,7 @@ where
fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
use crate::infer::type_variable::TypeVariableValue;
debug!("TypeGeneralizer::tys(a={:?})", a,);
debug!("TypeGeneralizer::tys(a={:?})", a);
match a.sty {
ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_))
@ -934,7 +950,7 @@ where
a: ty::Region<'tcx>,
_: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("TypeGeneralizer::regions(a={:?})", a,);
debug!("TypeGeneralizer::regions(a={:?})", a);
if let ty::ReLateBound(debruijn, _) = a {
if *debruijn < self.first_free_index {
@ -963,6 +979,23 @@ where
Ok(replacement_region_vid)
}
fn consts(
&mut self,
a: &'tcx ty::Const<'tcx>,
_: &'tcx ty::Const<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
debug!("TypeGeneralizer::consts(a={:?})", a);
if let ty::Const { val: ConstValue::Infer(InferConst::Canonical(_, _)), .. } = a {
bug!(
"unexpected inference variable encountered in NLL generalization: {:?}",
a
);
} else {
relate::super_relate_consts(self, a, a)
}
}
fn binders<T>(
&mut self,
a: &ty::Binder<T>,
@ -971,7 +1004,7 @@ where
where
T: Relate<'tcx>,
{
debug!("TypeGeneralizer::binders(a={:?})", a,);
debug!("TypeGeneralizer::binders(a={:?})", a);
self.first_free_index.shift_in(1);
let result = self.relate(a.skip_binder(), a.skip_binder())?;

View File

@ -676,8 +676,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
let tcx = self.infcx.tcx;
value.fold_with(&mut BottomUpFolder {
tcx,
reg_op: |reg| reg,
fldop: |ty| {
ty_op: |ty| {
if let ty::Opaque(def_id, substs) = ty.sty {
// Check that this is `impl Trait` type is
// declared by `parent_def_id` -- i.e., one whose
@ -776,6 +775,8 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
ty
},
lt_op: |lt| lt,
ct_op: |ct| ct,
})
}

View File

@ -1,5 +1,6 @@
use super::{InferCtxt, FixupError, FixupResult, Span, type_variable::TypeVariableOrigin};
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
use crate::mir::interpret::ConstValue;
use crate::ty::{self, Ty, TyCtxt, TypeFoldable, InferConst};
use crate::ty::fold::{TypeFolder, TypeVisitor};
///////////////////////////////////////////////////////////////////////////
@ -72,6 +73,15 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeAndRegionResolv
r,
}
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if !ct.needs_infer() {
ct // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let c0 = self.infcx.shallow_resolve(ct);
c0.super_fold_with(self)
}
}
}
///////////////////////////////////////////////////////////////////////////
@ -136,7 +146,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'gcx, 'tcx>
/// their concrete results. If any variable cannot be replaced (never unified, etc)
/// then an `Err` result is returned.
pub fn fully_resolve<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
value: &T) -> FixupResult<T>
value: &T) -> FixupResult<'tcx, T>
where T : TypeFoldable<'tcx>
{
let mut full_resolver = FullTypeResolver { infcx: infcx, err: None };
@ -151,7 +161,7 @@ pub fn fully_resolve<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
// `err` field is not enforcable otherwise.
struct FullTypeResolver<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
err: Option<FixupError>,
err: Option<FixupError<'tcx>>,
}
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> {
@ -199,4 +209,25 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx>
_ => r,
}
}
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if !c.needs_infer() && !ty::keep_local(&c) {
c // micro-optimize -- if there is nothing in this const that this fold affects...
// ^ we need to have the `keep_local` check to un-default
// defaulted tuples.
} else {
let c = self.infcx.shallow_resolve(c);
match c.val {
ConstValue::Infer(InferConst::Var(vid)) => {
self.err = Some(FixupError::UnresolvedConst(vid));
return self.tcx().consts.err;
}
ConstValue::Infer(InferConst::Fresh(_)) => {
bug!("Unexpected const in full const resolver: {:?}", c);
}
_ => {}
}
c.super_fold_with(self)
}
}
}

View File

@ -1,11 +1,13 @@
use super::SubregionOrigin;
use super::combine::{CombineFields, RelationDir};
use super::combine::{CombineFields, RelationDir, const_unification_error};
use crate::traits::Obligation;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{self, Ty, TyCtxt, InferConst};
use crate::ty::TyVar;
use crate::ty::fold::TypeFoldable;
use crate::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
use crate::infer::unify_key::replace_if_possible;
use crate::mir::interpret::ConstValue;
use std::mem;
/// Ensures `a` is made a subtype of `b`. Returns `a` on success.
@ -133,6 +135,48 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
Ok(a)
}
fn consts(
&mut self,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
if a == b { return Ok(a); }
let infcx = self.fields.infcx;
let a = replace_if_possible(infcx.const_unification_table.borrow_mut(), a);
let b = replace_if_possible(infcx.const_unification_table.borrow_mut(), b);
// Consts can only be equal or unequal to each other: there's no subtyping
// relation, so we're just going to perform equating here instead.
let a_is_expected = self.a_is_expected();
match (a.val, b.val) {
(ConstValue::Infer(InferConst::Var(a_vid)),
ConstValue::Infer(InferConst::Var(b_vid))) => {
infcx.const_unification_table
.borrow_mut()
.unify_var_var(a_vid, b_vid)
.map_err(|e| const_unification_error(a_is_expected, e))?;
return Ok(a);
}
(ConstValue::Infer(InferConst::Var(a_id)), _) => {
self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?;
return Ok(a);
}
(_, ConstValue::Infer(InferConst::Var(b_id))) => {
self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?;
return Ok(a);
}
_ => {}
}
self.fields.infcx.super_combine_consts(self, a, b)?;
Ok(a)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>

View File

@ -17,7 +17,7 @@ pub struct TypeVariableTable<'tcx> {
/// the known value.
eq_relations: ut::UnificationTable<ut::InPlace<TyVidEqKey<'tcx>>>,
/// Two variables are unified in `eq_relations` when we have a
/// Two variables are unified in `sub_relations` when we have a
/// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second
/// table exists only to help with the occurs check. In particular,
/// we want to report constraints like these as an occurs check
@ -365,7 +365,7 @@ impl sv::SnapshotVecDelegate for Delegate {
fn reverse(_values: &mut Vec<TypeVariableData>, _action: Instantiate) {
// We don't actually have to *do* anything to reverse an
// instanation; the value for a variable is stored in the
// instantiation; the value for a variable is stored in the
// `eq_relations` and hence its rollback code will handle
// it. In fact, we could *almost* just remove the
// `SnapshotVec` entirely, except that we would have to

View File

@ -1,5 +1,13 @@
use crate::ty::{self, FloatVarValue, IntVarValue, Ty, TyCtxt};
use rustc_data_structures::unify::{NoError, EqUnifyValue, UnifyKey, UnifyValue};
use crate::ty::{self, FloatVarValue, IntVarValue, Ty, TyCtxt, InferConst};
use crate::mir::interpret::ConstValue;
use rustc_data_structures::unify::{NoError, EqUnifyValue, UnifyKey, UnifyValue, UnificationTable};
use rustc_data_structures::unify::InPlace;
use syntax_pos::{Span, DUMMY_SP};
use syntax::symbol::InternedString;
use std::cmp;
use std::marker::PhantomData;
use std::cell::RefMut;
pub trait ToType {
fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
@ -12,8 +20,7 @@ impl UnifyKey for ty::IntVid {
fn tag() -> &'static str { "IntVid" }
}
impl EqUnifyValue for IntVarValue {
}
impl EqUnifyValue for IntVarValue {}
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RegionVidKey {
@ -62,11 +69,114 @@ impl UnifyKey for ty::FloatVid {
fn tag() -> &'static str { "FloatVid" }
}
impl EqUnifyValue for FloatVarValue {
}
impl EqUnifyValue for FloatVarValue {}
impl ToType for FloatVarValue {
fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
tcx.mk_mach_float(self.0)
}
}
// Generic consts.
/// Reasons to create a const inference variable
#[derive(Copy, Clone, Debug)]
pub enum ConstVariableOrigin {
MiscVariable(Span),
ConstInference(Span),
ConstParameterDefinition(Span, InternedString),
SubstitutionPlaceholder(Span),
}
#[derive(Copy, Clone, Debug)]
pub enum ConstVariableValue<'tcx> {
Known { value: &'tcx ty::Const<'tcx> },
Unknown { universe: ty::UniverseIndex },
}
impl<'tcx> ConstVariableValue<'tcx> {
/// If this value is known, returns the const it is known to be.
/// Otherwise, `None`.
pub fn known(&self) -> Option<&'tcx ty::Const<'tcx>> {
match *self {
ConstVariableValue::Unknown { .. } => None,
ConstVariableValue::Known { value } => Some(value),
}
}
pub fn is_unknown(&self) -> bool {
match *self {
ConstVariableValue::Unknown { .. } => true,
ConstVariableValue::Known { .. } => false,
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct ConstVarValue<'tcx> {
pub origin: ConstVariableOrigin,
pub val: ConstVariableValue<'tcx>,
}
impl<'tcx> UnifyKey for ty::ConstVid<'tcx> {
type Value = ConstVarValue<'tcx>;
fn index(&self) -> u32 { self.index }
fn from_index(i: u32) -> Self { ty::ConstVid { index: i, phantom: PhantomData } }
fn tag() -> &'static str { "ConstVid" }
}
impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>);
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
let val = match (value1.val, value2.val) {
(
ConstVariableValue::Known { .. },
ConstVariableValue::Known { .. }
) => {
bug!("equating two const variables, both of which have known values")
}
// If one side is known, prefer that one.
(ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => {
Ok(value1.val)
}
(ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => {
Ok(value2.val)
}
// If both sides are *unknown*, it hardly matters, does it?
(ConstVariableValue::Unknown { universe: universe1 },
ConstVariableValue::Unknown { universe: universe2 }) => {
// If we unify two unbound variables, ?T and ?U, then whatever
// value they wind up taking (which must be the same value) must
// be nameable by both universes. Therefore, the resulting
// universe is the minimum of the two universes, because that is
// the one which contains the fewest names in scope.
let universe = cmp::min(universe1, universe2);
Ok(ConstVariableValue::Unknown { universe })
}
}?;
Ok(ConstVarValue {
origin: ConstVariableOrigin::ConstInference(DUMMY_SP),
val,
})
}
}
impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {}
pub fn replace_if_possible(
mut table: RefMut<'_, UnificationTable<InPlace<ty::ConstVid<'tcx>>>>,
c: &'tcx ty::Const<'tcx>
) -> &'tcx ty::Const<'tcx> {
if let ty::Const { val: ConstValue::Infer(InferConst::Var(vid)), .. } = c {
match table.probe_value(*vid).val.known() {
Some(c) => c,
None => c,
}
} else {
c
}
}

View File

@ -2,6 +2,7 @@ use std::fmt;
use rustc_macros::HashStable;
use crate::ty::{Ty, InferConst, ParamConst, layout::{HasDataLayout, Size}, subst::SubstsRef};
use crate::ty::PlaceholderConst;
use crate::hir::def_id::DefId;
use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
@ -26,6 +27,9 @@ pub enum ConstValue<'tcx> {
/// Infer the value of the const.
Infer(InferConst<'tcx>),
/// A placeholder const - universally quantified higher-ranked const.
Placeholder(PlaceholderConst),
/// Used only for types with `layout::abi::Scalar` ABI and ZSTs.
///
/// Not using the enum `Value` to encode that this must not be `Undef`.
@ -58,6 +62,7 @@ impl<'tcx> ConstValue<'tcx> {
match *self {
ConstValue::Param(_) |
ConstValue::Infer(_) |
ConstValue::Placeholder(_) |
ConstValue::ByRef(..) |
ConstValue::Unevaluated(..) |
ConstValue::Slice(..) => None,

View File

@ -1248,7 +1248,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let sig = if let ty::Tuple(inputs) = inputs.sty {
tcx.mk_fn_sig(
inputs.iter().map(|k| k.expect_ty()),
tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })),
tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
false,
hir::Unsafety::Normal,
::rustc_target::spec::abi::Abi::Rust
@ -1256,7 +1256,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} else {
tcx.mk_fn_sig(
::std::iter::once(inputs),
tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })),
tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
false,
hir::Unsafety::Normal,
::rustc_target::spec::abi::Abi::Rust

View File

@ -1,4 +1,4 @@
use crate::infer::InferCtxt;
use crate::infer::{InferCtxt, ShallowResolver};
use crate::mir::interpret::{GlobalId, ErrorHandled};
use crate::ty::{self, Ty, TypeFoldable, ToPolyTraitRef};
use crate::ty::error::ExpectedFound;
@ -256,8 +256,8 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
if !pending_obligation.stalled_on.is_empty() {
if pending_obligation.stalled_on.iter().all(|&ty| {
// Use the force-inlined variant of shallow_resolve() because this code is hot.
let resolved_ty = self.selcx.infcx().inlined_shallow_resolve(&ty);
resolved_ty == ty // nothing changed here
let resolved = ShallowResolver::new(self.selcx.infcx()).inlined_shallow_resolve(ty);
resolved == ty // nothing changed here
}) {
debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
self.selcx.infcx()

View File

@ -1371,7 +1371,7 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
let tcx = selcx.tcx();
let infcx = selcx.infcx();
let closure_sig_ty = vtable.substs.closure_sig_ty(vtable.closure_def_id, tcx);
let closure_sig = infcx.shallow_resolve(&closure_sig_ty).fn_sig(tcx);
let closure_sig = infcx.shallow_resolve(closure_sig_ty).fn_sig(tcx);
let Normalized {
value: closure_sig,
obligations

View File

@ -3124,8 +3124,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// OK to skip binder because the substs on generator types never
// touch bound regions, they just capture the in-scope
// type/region parameters
let self_ty = self.infcx
.shallow_resolve(obligation.self_ty().skip_binder());
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
let (generator_def_id, substs) = match self_ty.sty {
ty::Generator(id, substs, _) => (id, substs),
_ => bug!("closure candidate for non-closure {:?}", obligation),
@ -3182,8 +3181,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// OK to skip binder because the substs on closure types never
// touch bound regions, they just capture the in-scope
// type/region parameters
let self_ty = self.infcx
.shallow_resolve(obligation.self_ty().skip_binder());
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
let (closure_def_id, substs) = match self_ty.sty {
ty::Closure(id, substs) => (id, substs),
_ => bug!("closure candidate for non-closure {:?}", obligation),

View File

@ -1,6 +1,7 @@
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{self, Ty, TyCtxt, InferConst};
use crate::ty::error::TypeError;
use crate::ty::relate::{self, Relate, TypeRelation, RelateResult};
use crate::mir::interpret::ConstValue;
/// A type "A" *matches* "B" if the fresh types in B could be
/// substituted with values so as to make it equal to A. Matching is
@ -78,6 +79,31 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Match<'a, 'gcx, 'tcx> {
}
}
fn consts(
&mut self,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
if a == b {
return Ok(a);
}
match (a.val, b.val) {
(_, ConstValue::Infer(InferConst::Fresh(_))) => {
return Ok(a);
}
(ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => {
return Err(TypeError::ConstMismatch(relate::expected_found(self, &a, &b)));
}
_ => {}
}
relate::super_relate_consts(self, a, b)
}
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
where T: Relate<'tcx>

View File

@ -233,6 +233,10 @@ pub struct CommonLifetimes<'tcx> {
pub re_erased: Region<'tcx>,
}
pub struct CommonConsts<'tcx> {
pub err: &'tcx Const<'tcx>,
}
pub struct LocalTableInContext<'a, V: 'a> {
local_id_root: Option<DefId>,
data: &'a ItemLocalMap<V>
@ -980,6 +984,20 @@ impl<'tcx> CommonLifetimes<'tcx> {
}
}
impl<'tcx> CommonConsts<'tcx> {
fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonConsts<'tcx> {
let mk_const = |c| {
interners.const_.borrow_mut().intern(c, |c| {
Interned(interners.arena.alloc(c))
}).0
};
CommonConsts {
err: mk_const(ty::Const::zero_sized(types.err)),
}
}
}
// This struct contains information regarding the `ReFree(FreeRegion)` corresponding to a lifetime
// conflict.
#[derive(Debug)]
@ -1030,6 +1048,9 @@ pub struct GlobalCtxt<'tcx> {
/// Common lifetimes, pre-interned for your convenience.
pub lifetimes: CommonLifetimes<'tcx>,
/// Common consts, pre-interned for your convenience.
pub consts: CommonConsts<'tcx>,
/// Map indicating what traits are in scope for places where this
/// is relevant; generated by resolve.
trait_map: FxHashMap<DefIndex,
@ -1229,6 +1250,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
let interners = CtxtInterners::new(&arenas.interner);
let common_types = CommonTypes::new(&interners);
let common_lifetimes = CommonLifetimes::new(&interners);
let common_consts = CommonConsts::new(&interners, &common_types);
let dep_graph = hir.dep_graph.clone();
let max_cnum = cstore.crates_untracked().iter().map(|c| c.as_usize()).max().unwrap_or(0);
let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1);
@ -1284,6 +1306,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
dep_graph,
types: common_types,
lifetimes: common_lifetimes,
consts: common_consts,
trait_map,
export_map: resolutions.export_map.into_iter().map(|(k, v)| {
let exports: Vec<_> = v.into_iter().map(|e| {
@ -2650,7 +2673,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
#[inline]
pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> {
self.mk_infer(TyVar(v))
self.mk_ty_infer(TyVar(v))
}
#[inline]
@ -2663,19 +2686,31 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
#[inline]
pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> {
self.mk_infer(IntVar(v))
self.mk_ty_infer(IntVar(v))
}
#[inline]
pub fn mk_float_var(self, v: FloatVid) -> Ty<'tcx> {
self.mk_infer(FloatVar(v))
self.mk_ty_infer(FloatVar(v))
}
#[inline]
pub fn mk_infer(self, it: InferTy) -> Ty<'tcx> {
pub fn mk_ty_infer(self, it: InferTy) -> Ty<'tcx> {
self.mk_ty(Infer(it))
}
#[inline]
pub fn mk_const_infer(
self,
ic: InferConst<'tcx>,
ty: Ty<'tcx>,
) -> &'tcx ty::Const<'tcx> {
self.mk_const(ty::Const {
val: ConstValue::Infer(ic),
ty,
})
}
#[inline]
pub fn mk_ty_param(self,
index: u32,

View File

@ -44,6 +44,8 @@ pub enum TypeError<'tcx> {
ProjectionMismatched(ExpectedFound<DefId>),
ProjectionBoundsLength(ExpectedFound<usize>),
ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
@ -163,6 +165,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
report_maybe_different(f, &format!("trait `{}`", values.expected),
&format!("trait `{}`", values.found))
}
ConstMismatch(ref values) => {
write!(f, "expected `{:?}`, found `{:?}`", values.expected, values.found)
}
}
}
}

View File

@ -254,6 +254,9 @@ impl FlagComputation {
ConstValue::Param(_) => {
self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES | TypeFlags::HAS_PARAMS);
}
ConstValue::Placeholder(_) => {
self.add_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_CT_PLACEHOLDER);
}
_ => {},
}
}

View File

@ -32,6 +32,7 @@
//! looking for, and does not need to visit anything else.
use crate::hir::def_id::DefId;
use crate::mir::interpret::ConstValue;
use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags, flags::FlagComputation};
use std::collections::BTreeMap;
@ -96,7 +97,11 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
)
}
fn has_placeholders(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER)
self.has_type_flags(
TypeFlags::HAS_RE_PLACEHOLDER |
TypeFlags::HAS_TY_PLACEHOLDER |
TypeFlags::HAS_CT_PLACEHOLDER
)
}
fn needs_subst(&self) -> bool {
self.has_type_flags(TypeFlags::NEEDS_SUBST)
@ -193,29 +198,37 @@ pub trait TypeVisitor<'tcx> : Sized {
///////////////////////////////////////////////////////////////////////////
// Some sample folders
pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F, G>
pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F, G, H>
where F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
H: FnMut(&'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>,
{
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
pub fldop: F,
pub reg_op: G,
pub ty_op: F,
pub lt_op: G,
pub ct_op: H,
}
impl<'a, 'gcx, 'tcx, F, G> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F, G>
impl<'a, 'gcx, 'tcx, F, G, H> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F, G, H>
where F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
H: FnMut(&'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>,
{
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
let t1 = ty.super_fold_with(self);
(self.fldop)(t1)
let t = ty.super_fold_with(self);
(self.ty_op)(t)
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
let r = r.super_fold_with(self);
(self.reg_op)(r)
(self.lt_op)(r)
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
let ct = ct.super_fold_with(self);
(self.ct_op)(ct)
}
}
@ -422,22 +435,26 @@ struct BoundVarReplacer<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a),
fld_c: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx> + 'a),
}
impl<'a, 'gcx, 'tcx> BoundVarReplacer<'a, 'gcx, 'tcx> {
fn new<F, G>(
fn new<F, G, H>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
fld_r: &'a mut F,
fld_t: &'a mut G
fld_t: &'a mut G,
fld_c: &'a mut H,
) -> Self
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
G: FnMut(ty::BoundTy) -> Ty<'tcx>
G: FnMut(ty::BoundTy) -> Ty<'tcx>,
H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>,
{
BoundVarReplacer {
tcx,
current_index: ty::INNERMOST,
fld_r,
fld_t,
fld_c,
}
}
}
@ -497,6 +514,32 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for BoundVarReplacer<'a, 'gcx, 'tcx>
_ => r
}
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if let ty::Const {
val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, bound_const)),
ty,
} = *ct {
if debruijn == self.current_index {
let fld_c = &mut self.fld_c;
let ct = fld_c(bound_const, ty);
ty::fold::shift_vars(
self.tcx,
&ct,
self.current_index.as_u32()
)
} else {
ct
}
} else {
if !ct.has_vars_bound_at_or_above(self.current_index) {
// Nothing more to substitute.
ct
} else {
ct.super_fold_with(self)
}
}
}
}
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
@ -519,27 +562,34 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
T: TypeFoldable<'tcx>
{
// identity for bound types
// identity for bound types and consts
let fld_t = |bound_ty| self.mk_ty(ty::Bound(ty::INNERMOST, bound_ty));
self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t)
let fld_c = |bound_ct, ty| {
self.mk_const_infer(ty::InferConst::Canonical(ty::INNERMOST, bound_ct), ty)
};
self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c)
}
/// Replaces all escaping bound vars. The `fld_r` closure replaces escaping
/// bound regions while the `fld_t` closure replaces escaping bound types.
pub fn replace_escaping_bound_vars<T, F, G>(
/// bound regions; the `fld_t` closure replaces escaping bound types and the `fld_c`
/// closure replaces escaping bound consts.
pub fn replace_escaping_bound_vars<T, F, G, H>(
self,
value: &T,
mut fld_r: F,
mut fld_t: G
mut fld_t: G,
mut fld_c: H,
) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
G: FnMut(ty::BoundTy) -> Ty<'tcx>,
T: TypeFoldable<'tcx>
H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>,
T: TypeFoldable<'tcx>,
{
use rustc_data_structures::fx::FxHashMap;
let mut region_map = BTreeMap::new();
let mut type_map = FxHashMap::default();
let mut const_map = FxHashMap::default();
if !value.has_escaping_bound_vars() {
(value.clone(), region_map)
@ -552,7 +602,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
*type_map.entry(bound_ty).or_insert_with(|| fld_t(bound_ty))
};
let mut replacer = BoundVarReplacer::new(self, &mut real_fld_r, &mut real_fld_t);
let mut real_fld_c = |bound_ct, ty| {
*const_map.entry(bound_ct).or_insert_with(|| fld_c(bound_ct, ty))
};
let mut replacer = BoundVarReplacer::new(
self,
&mut real_fld_r,
&mut real_fld_t,
&mut real_fld_c,
);
let result = value.fold_with(&mut replacer);
(result, region_map)
}
@ -561,17 +620,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// Replaces all types or regions bound by the given `Binder`. The `fld_r`
/// closure replaces bound regions while the `fld_t` closure replaces bound
/// types.
pub fn replace_bound_vars<T, F, G>(
pub fn replace_bound_vars<T, F, G, H>(
self,
value: &Binder<T>,
fld_r: F,
fld_t: G
fld_t: G,
fld_c: H,
) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
G: FnMut(ty::BoundTy) -> Ty<'tcx>,
H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>,
T: TypeFoldable<'tcx>
{
self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t)
self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c)
}
/// Replaces any late-bound regions bound in `value` with
@ -732,6 +793,28 @@ impl TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> {
_ => ty.super_fold_with(self),
}
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if let ty::Const {
val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, bound_const)),
ty,
} = *ct {
if self.amount == 0 || debruijn < self.current_index {
ct
} else {
let debruijn = match self.direction {
Direction::In => debruijn.shifted_in(self.amount),
Direction::Out => {
assert!(debruijn.as_u32() >= self.amount);
debruijn.shifted_out(self.amount)
}
};
self.tcx.mk_const_infer(ty::InferConst::Canonical(debruijn, bound_const), ty)
}
} else {
ct.super_fold_with(self)
}
}
}
pub fn shift_region<'a, 'gcx, 'tcx>(
@ -824,6 +907,17 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
// visited.
r.bound_at_or_above_binder(self.outer_index)
}
fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> bool {
if let ty::Const {
val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, _)),
..
} = *ct {
debruijn >= self.outer_index
} else {
false
}
}
}
struct HasTypeFlagsVisitor {

View File

@ -96,6 +96,7 @@ mod constness;
pub mod error;
mod erase_regions;
pub mod fast_reject;
pub mod flags;
pub mod fold;
pub mod inhabitedness;
pub mod layout;
@ -112,7 +113,6 @@ pub mod wf;
pub mod util;
mod context;
mod flags;
mod instance;
mod structural_impls;
mod sty;
@ -455,6 +455,7 @@ bitflags! {
const HAS_TY_PLACEHOLDER = 1 << 14;
const HAS_CT_INFER = 1 << 15;
const HAS_CT_PLACEHOLDER = 1 << 16;
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
@ -477,7 +478,8 @@ bitflags! {
TypeFlags::HAS_FREE_LOCAL_NAMES.bits |
TypeFlags::KEEP_IN_LOCAL_TCX.bits |
TypeFlags::HAS_RE_LATE_BOUND.bits |
TypeFlags::HAS_TY_PLACEHOLDER.bits;
TypeFlags::HAS_TY_PLACEHOLDER.bits |
TypeFlags::HAS_CT_PLACEHOLDER.bits;
}
}
@ -1630,6 +1632,8 @@ pub type PlaceholderRegion = Placeholder<BoundRegion>;
pub type PlaceholderType = Placeholder<BoundVar>;
pub type PlaceholderConst = Placeholder<BoundVar>;
/// When type checking, we use the `ParamEnv` to track
/// details about the set of where-clauses that are in scope at this
/// particular point.

View File

@ -712,7 +712,7 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
// in order to place the projections inside the `<...>`.
if !resugared {
// Use a type that can't appear in defaults of type parameters.
let dummy_self = self.tcx().mk_infer(ty::FreshTy(0));
let dummy_self = self.tcx().mk_ty_infer(ty::FreshTy(0));
let principal = principal.with_self_ty(self.tcx(), dummy_self);
let args = self.generic_args_to_print(
@ -1481,7 +1481,7 @@ define_print_and_forward_display! {
ty::ExistentialTraitRef<'tcx> {
// Use a type that can't appear in defaults of type parameters.
let dummy_self = cx.tcx().mk_infer(ty::FreshTy(0));
let dummy_self = cx.tcx().mk_ty_infer(ty::FreshTy(0));
let trait_ref = self.with_self_ty(cx.tcx(), dummy_self);
p!(print(trait_ref))
}

View File

@ -8,7 +8,7 @@ use crate::hir::def_id::DefId;
use crate::ty::subst::{Kind, UnpackedKind, SubstsRef};
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
use crate::ty::error::{ExpectedFound, TypeError};
use crate::mir::interpret::{GlobalId, ConstValue};
use crate::mir::interpret::{GlobalId, ConstValue, Scalar};
use crate::util::common::ErrorReported;
use syntax_pos::DUMMY_SP;
use std::rc::Rc;
@ -76,11 +76,19 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized {
// additional hooks for other types in the future if needed
// without making older code, which called `relate`, obsolete.
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>)
-> RelateResult<'tcx, Ty<'tcx>>;
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>;
fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
-> RelateResult<'tcx, ty::Region<'tcx>>;
fn regions(
&mut self,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>
) -> RelateResult<'tcx, ty::Region<'tcx>>;
fn consts(
&mut self,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>;
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
@ -116,7 +124,7 @@ impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> {
ast::Mutability::MutMutable => ty::Invariant,
};
let ty = relation.relate_with_variance(variance, &a.ty, &b.ty)?;
Ok(ty::TypeAndMut {ty: ty, mutbl: mutbl})
Ok(ty::TypeAndMut { ty, mutbl })
}
}
}
@ -468,6 +476,8 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
let t = relation.relate(&a_t, &b_t)?;
let to_u64 = |x: ty::Const<'tcx>| -> Result<u64, ErrorReported> {
match x.val {
// FIXME(const_generics): this doesn't work right now,
// because it tries to relate an `Infer` to a `Param`.
ConstValue::Unevaluated(def_id, substs) => {
// FIXME(eddyb) get the right param_env.
let param_env = ty::ParamEnv::empty();
@ -481,7 +491,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None
promoted: None,
};
if let Some(s) = tcx.const_eval(param_env.and(cid))
.ok()
@ -575,6 +585,62 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
}
}
/// The main "const relation" routine. Note that this does not handle
/// inference artifacts, so you should filter those out before calling
/// it.
pub fn super_relate_consts<'a, 'gcx, 'tcx, R>(
relation: &mut R,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>
where
R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
{
let tcx = relation.tcx();
// Currently, the values that can be unified are those that
// implement both `PartialEq` and `Eq`, corresponding to
// `structural_match` types.
// FIXME(const_generics): check for `structural_match` synthetic attribute.
match (a.val, b.val) {
(ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => {
// The caller should handle these cases!
bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
}
(ConstValue::Param(a_p), ConstValue::Param(b_p)) if a_p.index == b_p.index => {
Ok(a)
}
(ConstValue::Placeholder(p1), ConstValue::Placeholder(p2)) if p1 == p2 => {
Ok(a)
}
(ConstValue::Scalar(Scalar::Bits { .. }), _) if a == b => {
Ok(a)
}
(ConstValue::ByRef(..), _) => {
bug!(
"non-Scalar ConstValue encountered in super_relate_consts {:?} {:?}",
a,
b,
);
}
// FIXME(const_generics): this is wrong, as it is a projection
(ConstValue::Unevaluated(a_def_id, a_substs),
ConstValue::Unevaluated(b_def_id, b_substs)) if a_def_id == b_def_id => {
let substs =
relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
Ok(tcx.mk_const(ty::Const {
val: ConstValue::Unevaluated(a_def_id, &substs),
ty: a.ty,
}))
}
_ => {
Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
}
}
}
impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
fn relate<'a, 'gcx, R>(relation: &mut R,
a: &Self,
@ -646,6 +712,17 @@ impl<'tcx> Relate<'tcx> for ty::Region<'tcx> {
}
}
impl<'tcx> Relate<'tcx> for &'tcx ty::Const<'tcx> {
fn relate<'a, 'gcx, R>(relation: &mut R,
a: &&'tcx ty::Const<'tcx>,
b: &&'tcx ty::Const<'tcx>)
-> RelateResult<'tcx, &'tcx ty::Const<'tcx>>
where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
{
relation.consts(*a, *b)
}
}
impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder<T> {
fn relate<'a, 'gcx, R>(relation: &mut R,
a: &ty::Binder<T>,
@ -699,14 +776,17 @@ impl<'tcx> Relate<'tcx> for Kind<'tcx> {
(UnpackedKind::Type(a_ty), UnpackedKind::Type(b_ty)) => {
Ok(relation.relate(&a_ty, &b_ty)?.into())
}
(UnpackedKind::Const(a_ct), UnpackedKind::Const(b_ct)) => {
Ok(relation.relate(&a_ct, &b_ct)?.into())
}
(UnpackedKind::Lifetime(unpacked), x) => {
bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
}
(UnpackedKind::Type(unpacked), x) => {
bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
}
(UnpackedKind::Const(_), _) => {
unimplemented!() // FIXME(const_generics)
(UnpackedKind::Const(unpacked), x) => {
bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
}
}
}

View File

@ -737,7 +737,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
ProjectionMismatched(x) => ProjectionMismatched(x),
ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
Sorts(ref x) => return tcx.lift(x).map(Sorts),
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch),
})
}
}
@ -1320,6 +1321,7 @@ EnumTypeFoldableImpl! {
(ty::error::TypeError::ProjectionBoundsLength)(x),
(ty::error::TypeError::Sorts)(x),
(ty::error::TypeError::ExistentialMismatch)(x),
(ty::error::TypeError::ConstMismatch)(x),
}
}
@ -1353,6 +1355,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
// FIXME(const_generics): implement TypeFoldable for InferConst
ConstValue::Infer(ic) => ConstValue::Infer(ic),
ConstValue::Param(p) => ConstValue::Param(p.fold_with(folder)),
ConstValue::Placeholder(p) => ConstValue::Placeholder(p),
ConstValue::Scalar(a) => ConstValue::Scalar(a),
ConstValue::Slice(a, b) => ConstValue::Slice(a, b),
ConstValue::Unevaluated(did, substs)
@ -1364,8 +1367,9 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
match *self {
ConstValue::ByRef(..) => false,
// FIXME(const_generics): implement TypeFoldable for InferConst
ConstValue::Infer(_ic) => false,
ConstValue::Infer(_) => false,
ConstValue::Param(p) => p.visit_with(visitor),
ConstValue::Placeholder(_) => false,
ConstValue::Scalar(_) => false,
ConstValue::Slice(..) => false,
ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),

View File

@ -516,7 +516,7 @@ pub fn object_region_bounds<'a, 'gcx, 'tcx>(
// Since we don't actually *know* the self type for an object,
// this "open(err)" serves as a kind of dummy standin -- basically
// a placeholder type.
let open_ty = tcx.mk_infer(ty::FreshTy(0));
let open_ty = tcx.mk_ty_infer(ty::FreshTy(0));
let predicates = existential_predicates.iter().filter_map(|predicate| {
if let ty::ExistentialPredicate::Projection(_) = *predicate.skip_binder() {

View File

@ -79,6 +79,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
ConstValue::Unevaluated(..) => bug!("unevaluated constant in `OperandRef::from_const`"),
ConstValue::Param(_) => bug!("encountered a ConstValue::Param in codegen"),
ConstValue::Infer(_) => bug!("encountered a ConstValue::Infer in codegen"),
ConstValue::Placeholder(_) => bug!("encountered a ConstValue::Placeholder in codegen"),
ConstValue::Scalar(x) => {
let scalar = match layout.abi {
layout::Abi::Scalar(ref x) => x,

View File

@ -524,7 +524,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
layout: Option<TyLayout<'tcx>>,
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let op = match val.val {
ConstValue::Param(_) | ConstValue::Infer(_) => bug!(),
ConstValue::Param(_) => return err!(TooGeneric),
ConstValue::Infer(_) | ConstValue::Placeholder(_) => bug!(),
ConstValue::ByRef(ptr, alloc) => {
// We rely on mutability being set correctly in that allocation to prevent writes
// where none should happen -- and for `static mut`, we copy on demand anyway.

View File

@ -397,7 +397,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
// FIXME(const_generics): handle debug printing.
pub fn push_const_name(&self, c: &Const<'tcx>, output: &mut String, debug: bool) {
match c.val {
ConstValue::Infer(..) => output.push_str("_"),
ConstValue::Infer(..) | ConstValue::Placeholder(_) => output.push_str("_"),
ConstValue::Param(ParamConst { name, .. }) => {
write!(output, "{}", name).unwrap();
}

View File

@ -16,9 +16,10 @@ use rustc::traits::{
Environment,
InEnvironment,
};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::{self, Ty, TyCtxt, InferConst};
use rustc::ty::subst::Kind;
use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc::mir::interpret::ConstValue;
use syntax_pos::DUMMY_SP;
use super::{ChalkInferenceContext, ChalkArenas, ChalkExClause, ConstrainedSubst};
@ -275,4 +276,44 @@ impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> {
Ok(a)
}
fn consts(
&mut self,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
if let ty::Const {
val: ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)),
..
} = a {
if *debruijn == self.binder_index {
self.unify_free_answer_var(*bound_ct, b.into())?;
return Ok(b);
}
}
match (a, b) {
(
ty::Const {
val: ConstValue::Infer(InferConst::Canonical(a_debruijn, a_bound)),
..
},
ty::Const {
val: ConstValue::Infer(InferConst::Canonical(b_debruijn, b_bound)),
..
},
) => {
assert_eq!(a_debruijn, b_debruijn);
assert_eq!(a_bound, b_bound);
Ok(a)
}
// Everything else should just be a perfect match as well,
// and we forbid inference variables.
_ => match ty::relate::super_relate_consts(self, a, b) {
Ok(ct) => Ok(ct),
Err(err) => bug!("const mismatch in `AnswerSubstitutor`: {}", err),
}
}
}
}

View File

@ -21,6 +21,7 @@ use rustc::traits::query::method_autoderef::{MethodAutoderefBadTy};
use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
use rustc::ty::GenericParamDefKind;
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::infer::unify_key::ConstVariableOrigin;
use rustc::util::nodemap::FxHashSet;
use rustc::infer::{self, InferOk};
use rustc::infer::canonical::{Canonical, QueryResponse};
@ -1572,7 +1573,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
self.tcx.def_span(def_id))).into()
}
GenericParamDefKind::Const { .. } => {
unimplemented!() // FIXME(const_generics)
let span = self.tcx.def_span(def_id);
let origin = ConstVariableOrigin::SubstitutionPlaceholder(span);
self.next_const_var(self.tcx.type_of(param.def_id), origin).into()
}
}
})

View File

@ -616,7 +616,7 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
let mut substituted_predicates = Vec::new();
ty.fold_with(&mut ty::fold::BottomUpFolder {
tcx: fcx.tcx,
fldop: |ty| {
ty_op: |ty| {
if let ty::Opaque(def_id, substs) = ty.sty {
trace!("check_existential_types: opaque_ty, {:?}, {:?}", def_id, substs);
let generics = tcx.generics_of(def_id);
@ -739,7 +739,8 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
} // if let Opaque
ty
},
reg_op: |reg| reg,
lt_op: |lt| lt,
ct_op: |ct| ct,
});
substituted_predicates
}

View File

@ -12,6 +12,7 @@ use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder};
use rustc::ty::subst::UnpackedKind;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::mir::interpret::ConstValue;
use rustc::util::nodemap::DefIdSet;
use rustc_data_structures::sync::Lrc;
use std::mem;
@ -488,7 +489,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
// figures out the concrete type with `U`, but the stored type is with `T`
instantiated_ty.fold_with(&mut BottomUpFolder {
tcx: self.tcx().global_tcx(),
fldop: |ty| {
ty_op: |ty| {
trace!("checking type {:?}", ty);
// find a type parameter
if let ty::Param(..) = ty.sty {
@ -520,7 +521,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
}
ty
},
reg_op: |region| {
lt_op: |region| {
match region {
// ignore static regions
ty::ReStatic => region,
@ -564,6 +565,39 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
}
}
},
ct_op: |ct| {
trace!("checking const {:?}", ct);
// Find a const parameter
if let ConstValue::Param(..) = ct.val {
// look it up in the substitution list
assert_eq!(opaque_defn.substs.len(), generics.params.len());
for (subst, param) in opaque_defn.substs.iter()
.zip(&generics.params) {
if let UnpackedKind::Const(subst) = subst.unpack() {
if subst == ct {
// found it in the substitution list, replace with the
// parameter from the existential type
return self.tcx()
.global_tcx()
.mk_const_param(param.index, param.name, ct.ty);
}
}
}
self.tcx()
.sess
.struct_span_err(
span,
&format!(
"const parameter `{}` is part of concrete type but not \
used in parameter list for existential type",
ct,
),
)
.emit();
return self.tcx().consts.err;
}
ct
}
})
};
@ -819,6 +853,21 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
self.infcx.fully_resolve(&r).unwrap_or(self.tcx.lifetimes.re_static)
}
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
match self.infcx.fully_resolve(&ct) {
Ok(ct) => ct,
Err(_) => {
debug!(
"Resolver::fold_const: input const `{:?}` not fully resolvable",
ct
);
// FIXME: we'd like to use `self.report_error`, but it doesn't yet
// accept a &'tcx ty::Const.
self.tcx().consts.err
}
}
}
}
///////////////////////////////////////////////////////////////////////////

View File

@ -15,7 +15,7 @@
//! crate as a kind of pass. This should eventually be factored away.
use crate::astconv::{AstConv, Bounds};
use crate::constrained_generic_params as ctp;
use crate::constrained_generic_params as cgp;
use crate::check::intrinsic::intrisic_operation_unsafety;
use crate::lint;
use crate::middle::lang_items::SizedTraitLangItem;
@ -2202,11 +2202,11 @@ fn explicit_predicates_of<'a, 'tcx>(
{
let self_ty = tcx.type_of(def_id);
let trait_ref = tcx.impl_trait_ref(def_id);
ctp::setup_constraining_predicates(
cgp::setup_constraining_predicates(
tcx,
&mut predicates,
trait_ref,
&mut ctp::parameters_for_impl(self_ty, trait_ref),
&mut cgp::parameters_for_impl(self_ty, trait_ref),
);
}

View File

@ -8,7 +8,7 @@
//! specialization errors. These things can (and probably should) be
//! fixed, but for the moment it's easier to do these checks early.
use crate::constrained_generic_params as ctp;
use crate::constrained_generic_params as cgp;
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::def_id::DefId;
@ -102,8 +102,8 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let impl_predicates = tcx.predicates_of(impl_def_id);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref);
ctp::identify_constrained_generic_params(
let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
cgp::identify_constrained_generic_params(
tcx, &impl_predicates, impl_trait_ref, &mut input_parameters);
// Disallow unconstrained lifetimes, but only if they appear in assoc types.
@ -114,7 +114,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
item.kind == ty::AssociatedKind::Type && item.defaultness.has_value()
})
.flat_map(|def_id| {
ctp::parameters_for(&tcx.type_of(def_id), true)
cgp::parameters_for(&tcx.type_of(def_id), true)
}).collect();
for param in &impl_generics.params {
@ -122,7 +122,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Disallow ANY unconstrained type parameters.
ty::GenericParamDefKind::Type { .. } => {
let param_ty = ty::ParamTy::for_def(param);
if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
if !input_parameters.contains(&cgp::Parameter::from(param_ty)) {
report_unused_parameter(tcx,
tcx.def_span(param.def_id),
"type",
@ -130,7 +130,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
ty::GenericParamDefKind::Lifetime => {
let param_lt = ctp::Parameter::from(param.to_early_bound_region_data());
let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
if lifetimes_in_associated_types.contains(&param_lt) && // (*)
!input_parameters.contains(&param_lt) {
report_unused_parameter(tcx,
@ -141,7 +141,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
ty::GenericParamDefKind::Const => {
let param_ct = ty::ParamConst::for_def(param);
if !input_parameters.contains(&ctp::Parameter::from(param_ct)) {
if !input_parameters.contains(&cgp::Parameter::from(param_ct)) {
report_unused_parameter(tcx,
tcx.def_span(param.def_id),
"const",

View File

@ -0,0 +1,10 @@
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
fn foo<const X: usize>() -> usize {
0
}
fn main() {
foo(); //~ ERROR type annotations needed
}

View File

@ -0,0 +1,15 @@
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> $DIR/cannot-infer-const-args.rs:1:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
error[E0282]: type annotations needed
--> $DIR/cannot-infer-const-args.rs:9:5
|
LL | foo();
| ^^^ cannot infer type for `fn() -> usize {foo::<_>}`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0282`.

View File

@ -0,0 +1,13 @@
// run-pass
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
fn const_u32_identity<const X: u32>() -> u32 {
X
}
fn main() {
let val = const_u32_identity::<18>();
assert_eq!(val, 18);
}

View File

@ -0,0 +1,6 @@
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> $DIR/const-arg-in-fn.rs:3:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^

View File

@ -0,0 +1,16 @@
// run-pass
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
#[allow(dead_code)]
struct ConstArray<T, const LEN: usize> {
array: [T; LEN],
}
fn main() {
let arr = ConstArray::<i32, 8> {
array: [0; 8],
};
}

View File

@ -0,0 +1,6 @@
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> $DIR/const-types.rs:3:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^

View File

@ -0,0 +1,11 @@
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
fn foo<const X: usize, const Y: usize>() -> usize {
0
}
fn main() {
foo::<0>(); //~ ERROR wrong number of const arguments: expected 2, found 1
foo::<0, 0, 0>(); //~ ERROR wrong number of const arguments: expected 2, found 3
}

View File

@ -0,0 +1,21 @@
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> $DIR/incorrect-number-of-const-args.rs:1:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
error[E0107]: wrong number of const arguments: expected 2, found 1
--> $DIR/incorrect-number-of-const-args.rs:9:5
|
LL | foo::<0>();
| ^^^^^^^^ expected 2 const arguments
error[E0107]: wrong number of const arguments: expected 2, found 3
--> $DIR/incorrect-number-of-const-args.rs:10:17
|
LL | foo::<0, 0, 0>();
| ^ unexpected const argument
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0107`.