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:
commit
92b5e20ad5
@ -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,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
{
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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(\
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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())?;
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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() {
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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(¶m_lt) && // (*)
|
||||
!input_parameters.contains(¶m_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",
|
||||
|
10
src/test/ui/const-generics/cannot-infer-const-args.rs
Normal file
10
src/test/ui/const-generics/cannot-infer-const-args.rs
Normal 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
|
||||
}
|
15
src/test/ui/const-generics/cannot-infer-const-args.stderr
Normal file
15
src/test/ui/const-generics/cannot-infer-const-args.stderr
Normal 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`.
|
13
src/test/ui/const-generics/const-arg-in-fn.rs
Normal file
13
src/test/ui/const-generics/const-arg-in-fn.rs
Normal 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);
|
||||
}
|
6
src/test/ui/const-generics/const-arg-in-fn.stderr
Normal file
6
src/test/ui/const-generics/const-arg-in-fn.stderr
Normal 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)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
16
src/test/ui/const-generics/const-types.rs
Normal file
16
src/test/ui/const-generics/const-types.rs
Normal 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],
|
||||
};
|
||||
}
|
6
src/test/ui/const-generics/const-types.stderr
Normal file
6
src/test/ui/const-generics/const-types.stderr
Normal 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)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
11
src/test/ui/const-generics/incorrect-number-of-const-args.rs
Normal file
11
src/test/ui/const-generics/incorrect-number-of-const-args.rs
Normal 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
|
||||
}
|
@ -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`.
|
Loading…
x
Reference in New Issue
Block a user