Auto merge of #111221 - compiler-errors:yeet-generalizer, r=lcnr
Combine three generalizer implementations Fixes #111092 Fixes #109505 This code is a bit delicate and there were subtle changes between them, so I'll leave inline comments where further inspection is needed. Regarding this comment from #109813 -- "add tests triggering all codepaths: at least the combine and the const generalizer", can't really do that now, and I don't really know how we'd get a higher-ranked const error since non-lifetime binders doesn't *really* support `for<const ..>` (it errors out when you try to use it). r? `@lcnr`
This commit is contained in:
commit
ea54255501
13 changed files with 627 additions and 831 deletions
|
@ -26,24 +26,17 @@ use super::equate::Equate;
|
|||
use super::glb::Glb;
|
||||
use super::lub::Lub;
|
||||
use super::sub::Sub;
|
||||
use super::type_variable::TypeVariableValue;
|
||||
use super::{DefineOpaqueTypes, InferCtxt, MiscVariable, TypeTrace};
|
||||
use super::{DefineOpaqueTypes, InferCtxt, TypeTrace};
|
||||
use crate::infer::generalize::{self, CombineDelegate, Generalization};
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
use rustc_data_structures::sso::SsoHashMap;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::infer::canonical::OriginalQueryValues;
|
||||
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{
|
||||
self, AliasKind, FallibleTypeFolder, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable,
|
||||
TypeSuperFoldable, TypeVisitableExt,
|
||||
};
|
||||
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, AliasKind, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{IntType, UintType};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CombineFields<'infcx, 'tcx> {
|
||||
|
@ -55,13 +48,6 @@ pub struct CombineFields<'infcx, 'tcx> {
|
|||
pub define_opaque_types: DefineOpaqueTypes,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum RelationDir {
|
||||
SubtypeOf,
|
||||
SupertypeOf,
|
||||
EqTo,
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
pub fn super_combine_tys<R>(
|
||||
&self,
|
||||
|
@ -152,7 +138,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
Ok(a)
|
||||
}
|
||||
|
||||
_ => ty::relate::super_relate_tys(relation, a, b),
|
||||
_ => ty::relate::structurally_relate_tys(relation, a, b),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,11 +197,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
// matching in the solver.
|
||||
let a_error = self.tcx.const_error(a.ty(), guar);
|
||||
if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() {
|
||||
return self.unify_const_variable(vid, a_error);
|
||||
return self.unify_const_variable(vid, a_error, relation.param_env());
|
||||
}
|
||||
let b_error = self.tcx.const_error(b.ty(), guar);
|
||||
if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() {
|
||||
return self.unify_const_variable(vid, b_error);
|
||||
return self.unify_const_variable(vid, b_error, relation.param_env());
|
||||
}
|
||||
|
||||
return Ok(if relation.a_is_expected() { a_error } else { b_error });
|
||||
|
@ -237,11 +223,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
|
||||
(ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
|
||||
return self.unify_const_variable(vid, b);
|
||||
return self.unify_const_variable(vid, b, relation.param_env());
|
||||
}
|
||||
|
||||
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
|
||||
return self.unify_const_variable(vid, a);
|
||||
return self.unify_const_variable(vid, a, relation.param_env());
|
||||
}
|
||||
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
|
||||
if self.tcx.lazy_normalization() =>
|
||||
|
@ -252,7 +238,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
ty::relate::super_relate_consts(relation, a, b)
|
||||
ty::relate::structurally_relate_consts(relation, a, b)
|
||||
}
|
||||
|
||||
/// Unifies the const variable `target_vid` with the given constant.
|
||||
|
@ -294,24 +280,17 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
&self,
|
||||
target_vid: ty::ConstVid<'tcx>,
|
||||
ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>> {
|
||||
let (for_universe, span) = {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let variable_table = &mut inner.const_unification_table();
|
||||
let var_value = variable_table.probe_value(target_vid);
|
||||
match var_value.val {
|
||||
ConstVariableValue::Known { value } => {
|
||||
bug!("instantiating {:?} which has a known value {:?}", target_vid, value)
|
||||
}
|
||||
ConstVariableValue::Unknown { universe } => (universe, var_value.origin.span),
|
||||
}
|
||||
};
|
||||
let value = ct.try_fold_with(&mut ConstInferUnifier {
|
||||
infcx: self,
|
||||
span,
|
||||
for_universe,
|
||||
let span =
|
||||
self.inner.borrow_mut().const_unification_table().probe_value(target_vid).origin.span;
|
||||
let Generalization { value, needs_wf: _ } = generalize::generalize(
|
||||
self,
|
||||
&mut CombineDelegate { infcx: self, span, param_env },
|
||||
ct,
|
||||
target_vid,
|
||||
})?;
|
||||
ty::Variance::Invariant,
|
||||
)?;
|
||||
|
||||
self.inner.borrow_mut().const_unification_table().union_value(
|
||||
target_vid,
|
||||
|
@ -392,12 +371,10 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
pub fn instantiate(
|
||||
&mut self,
|
||||
a_ty: Ty<'tcx>,
|
||||
dir: RelationDir,
|
||||
ambient_variance: ty::Variance,
|
||||
b_vid: ty::TyVid,
|
||||
a_is_expected: bool,
|
||||
) -> RelateResult<'tcx, ()> {
|
||||
use self::RelationDir::*;
|
||||
|
||||
// Get the actual variable that b_vid has been inferred to
|
||||
debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown());
|
||||
|
||||
|
@ -412,7 +389,18 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
// `'?2` and `?3` are fresh region/type inference
|
||||
// variables. (Down below, we will relate `a_ty <: b_ty`,
|
||||
// adding constraints like `'x: '?2` and `?1 <: ?3`.)
|
||||
let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
|
||||
let Generalization { value: b_ty, needs_wf } = generalize::generalize(
|
||||
self.infcx,
|
||||
&mut CombineDelegate {
|
||||
infcx: self.infcx,
|
||||
param_env: self.param_env,
|
||||
span: self.trace.span(),
|
||||
},
|
||||
a_ty,
|
||||
b_vid,
|
||||
ambient_variance,
|
||||
)?;
|
||||
|
||||
debug!(?b_ty);
|
||||
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
|
||||
|
||||
|
@ -431,78 +419,23 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
// relations wind up attributed to the same spans. We need
|
||||
// to associate causes/spans with each of the relations in
|
||||
// the stack to get this right.
|
||||
match dir {
|
||||
EqTo => self.equate(a_is_expected).relate(a_ty, b_ty),
|
||||
SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty),
|
||||
SupertypeOf => self.sub(a_is_expected).relate_with_variance(
|
||||
match ambient_variance {
|
||||
ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty),
|
||||
ty::Variance::Covariant => self.sub(a_is_expected).relate(a_ty, b_ty),
|
||||
ty::Variance::Contravariant => self.sub(a_is_expected).relate_with_variance(
|
||||
ty::Contravariant,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
a_ty,
|
||||
b_ty,
|
||||
),
|
||||
ty::Variance::Bivariant => {
|
||||
unreachable!("no code should be generalizing bivariantly (currently)")
|
||||
}
|
||||
}?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempts to generalize `ty` for the type variable `for_vid`.
|
||||
/// This checks for cycle -- that is, whether the type `ty`
|
||||
/// references `for_vid`. The `dir` is the "direction" for which we
|
||||
/// a performing the generalization (i.e., are we producing a type
|
||||
/// that can be used as a supertype etc).
|
||||
///
|
||||
/// Preconditions:
|
||||
///
|
||||
/// - `for_vid` is a "root vid"
|
||||
#[instrument(skip(self), level = "trace", ret)]
|
||||
fn generalize(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
for_vid: ty::TyVid,
|
||||
dir: RelationDir,
|
||||
) -> RelateResult<'tcx, Generalization<'tcx>> {
|
||||
// Determine the ambient variance within which `ty` appears.
|
||||
// The surrounding equation is:
|
||||
//
|
||||
// ty [op] ty2
|
||||
//
|
||||
// where `op` is either `==`, `<:`, or `:>`. This maps quite
|
||||
// naturally.
|
||||
let ambient_variance = match dir {
|
||||
RelationDir::EqTo => ty::Invariant,
|
||||
RelationDir::SubtypeOf => ty::Covariant,
|
||||
RelationDir::SupertypeOf => ty::Contravariant,
|
||||
};
|
||||
|
||||
trace!(?ambient_variance);
|
||||
|
||||
let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) {
|
||||
v @ TypeVariableValue::Known { .. } => {
|
||||
bug!("instantiating {:?} which has a known value {:?}", for_vid, v,)
|
||||
}
|
||||
TypeVariableValue::Unknown { universe } => universe,
|
||||
};
|
||||
|
||||
trace!(?for_universe);
|
||||
trace!(?self.trace);
|
||||
|
||||
let mut generalize = Generalizer {
|
||||
infcx: self.infcx,
|
||||
cause: &self.trace.cause,
|
||||
for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid),
|
||||
for_universe,
|
||||
ambient_variance,
|
||||
needs_wf: false,
|
||||
root_ty: ty,
|
||||
param_env: self.param_env,
|
||||
cache: SsoHashMap::new(),
|
||||
};
|
||||
|
||||
let ty = generalize.relate(ty, ty)?;
|
||||
let needs_wf = generalize.needs_wf;
|
||||
Ok(Generalization { ty, needs_wf })
|
||||
}
|
||||
|
||||
pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.obligations.extend(obligations.into_iter());
|
||||
}
|
||||
|
@ -514,313 +447,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
struct Generalizer<'cx, 'tcx> {
|
||||
infcx: &'cx InferCtxt<'tcx>,
|
||||
|
||||
/// The span, used when creating new type variables and things.
|
||||
cause: &'cx ObligationCause<'tcx>,
|
||||
|
||||
/// The vid of the type variable that is in the process of being
|
||||
/// instantiated; if we find this within the type we are folding,
|
||||
/// that means we would have created a cyclic type.
|
||||
for_vid_sub_root: ty::TyVid,
|
||||
|
||||
/// The universe of the type variable that is in the process of
|
||||
/// being instantiated. Any fresh variables that we create in this
|
||||
/// process should be in that same universe.
|
||||
for_universe: ty::UniverseIndex,
|
||||
|
||||
/// Track the variance as we descend into the type.
|
||||
ambient_variance: ty::Variance,
|
||||
|
||||
/// See the field `needs_wf` in `Generalization`.
|
||||
needs_wf: bool,
|
||||
|
||||
/// The root type that we are generalizing. Used when reporting cycles.
|
||||
root_ty: Ty<'tcx>,
|
||||
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
||||
cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
|
||||
}
|
||||
|
||||
/// Result from a generalization operation. This includes
|
||||
/// not only the generalized type, but also a bool flag
|
||||
/// indicating whether further WF checks are needed.
|
||||
#[derive(Debug)]
|
||||
struct Generalization<'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
|
||||
/// If true, then the generalized type may not be well-formed,
|
||||
/// even if the source type is well-formed, so we should add an
|
||||
/// additional check to enforce that it is. This arises in
|
||||
/// particular around 'bivariant' type parameters that are only
|
||||
/// constrained by a where-clause. As an example, imagine a type:
|
||||
///
|
||||
/// struct Foo<A, B> where A: Iterator<Item = B> {
|
||||
/// data: A
|
||||
/// }
|
||||
///
|
||||
/// here, `A` will be covariant, but `B` is
|
||||
/// unconstrained. However, whatever it is, for `Foo` to be WF, it
|
||||
/// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`,
|
||||
/// then after generalization we will wind up with a type like
|
||||
/// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C,
|
||||
/// ?D>` (or `>:`), we will wind up with the requirement that `?A
|
||||
/// <: ?C`, but no particular relationship between `?B` and `?D`
|
||||
/// (after all, we do not know the variance of the normalized form
|
||||
/// of `A::Item` with respect to `A`). If we do nothing else, this
|
||||
/// may mean that `?D` goes unconstrained (as in #41677). So, in
|
||||
/// this scenario where we create a new type variable in a
|
||||
/// bivariant context, we set the `needs_wf` flag to true. This
|
||||
/// will force the calling code to check that `WF(Foo<?C, ?D>)`
|
||||
/// holds, which in turn implies that `?C::Item == ?D`. So once
|
||||
/// `?C` is constrained, that should suffice to restrict `?D`.
|
||||
needs_wf: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.param_env
|
||||
}
|
||||
|
||||
fn tag(&self) -> &'static str {
|
||||
"Generalizer"
|
||||
}
|
||||
|
||||
fn a_is_expected(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn binders<T>(
|
||||
&mut self,
|
||||
a: ty::Binder<'tcx, T>,
|
||||
b: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
|
||||
}
|
||||
|
||||
fn relate_item_substs(
|
||||
&mut self,
|
||||
item_def_id: DefId,
|
||||
a_subst: SubstsRef<'tcx>,
|
||||
b_subst: SubstsRef<'tcx>,
|
||||
) -> RelateResult<'tcx, SubstsRef<'tcx>> {
|
||||
if self.ambient_variance == ty::Variance::Invariant {
|
||||
// Avoid fetching the variance if we are in an invariant
|
||||
// context; no need, and it can induce dependency cycles
|
||||
// (e.g., #41849).
|
||||
relate::relate_substs(self, a_subst, b_subst)
|
||||
} else {
|
||||
let tcx = self.tcx();
|
||||
let opt_variances = tcx.variances_of(item_def_id);
|
||||
relate::relate_substs_with_variances(
|
||||
self,
|
||||
item_def_id,
|
||||
&opt_variances,
|
||||
a_subst,
|
||||
b_subst,
|
||||
true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
let old_ambient_variance = self.ambient_variance;
|
||||
self.ambient_variance = self.ambient_variance.xform(variance);
|
||||
|
||||
let result = self.relate(a, b);
|
||||
self.ambient_variance = old_ambient_variance;
|
||||
result
|
||||
}
|
||||
|
||||
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
|
||||
|
||||
if let Some(&result) = self.cache.get(&t) {
|
||||
return Ok(result);
|
||||
}
|
||||
debug!("generalize: t={:?}", t);
|
||||
|
||||
// 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.
|
||||
let result = match *t.kind() {
|
||||
ty::Infer(ty::TyVar(vid)) => {
|
||||
let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid);
|
||||
let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid);
|
||||
if sub_vid == self.for_vid_sub_root {
|
||||
// If sub-roots are equal, then `for_vid` and
|
||||
// `vid` are related via subtyping.
|
||||
Err(TypeError::CyclicTy(self.root_ty))
|
||||
} else {
|
||||
let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid);
|
||||
match probe {
|
||||
TypeVariableValue::Known { value: u } => {
|
||||
debug!("generalize: known value {:?}", u);
|
||||
self.relate(u, u)
|
||||
}
|
||||
TypeVariableValue::Unknown { universe } => {
|
||||
match self.ambient_variance {
|
||||
// Invariant: no need to make a fresh type variable.
|
||||
ty::Invariant => {
|
||||
if self.for_universe.can_name(universe) {
|
||||
return Ok(t);
|
||||
}
|
||||
}
|
||||
|
||||
// Bivariant: make a fresh var, but we
|
||||
// may need a WF predicate. See
|
||||
// comment on `needs_wf` field for
|
||||
// more info.
|
||||
ty::Bivariant => self.needs_wf = true,
|
||||
|
||||
// Co/contravariant: this will be
|
||||
// sufficiently constrained later on.
|
||||
ty::Covariant | ty::Contravariant => (),
|
||||
}
|
||||
|
||||
let origin =
|
||||
*self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
|
||||
let new_var_id = self
|
||||
.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.type_variables()
|
||||
.new_var(self.for_universe, origin);
|
||||
let u = self.tcx().mk_ty_var(new_var_id);
|
||||
|
||||
// Record that we replaced `vid` with `new_var_id` as part of a generalization
|
||||
// operation. This is needed to detect cyclic types. To see why, see the
|
||||
// docs in the `type_variables` module.
|
||||
self.infcx.inner.borrow_mut().type_variables().sub(vid, new_var_id);
|
||||
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
|
||||
Ok(u)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
|
||||
// No matter what mode we are in,
|
||||
// integer/floating-point types must be equal to be
|
||||
// relatable.
|
||||
Ok(t)
|
||||
}
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||
let s = self.relate(substs, substs)?;
|
||||
Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) })
|
||||
}
|
||||
_ => relate::super_relate_tys(self, t, t),
|
||||
}?;
|
||||
|
||||
self.cache.insert(t, result);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn regions(
|
||||
&mut self,
|
||||
r: ty::Region<'tcx>,
|
||||
r2: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
|
||||
|
||||
debug!("generalize: regions r={:?}", r);
|
||||
|
||||
match *r {
|
||||
// Never make variables for regions bound within the type itself,
|
||||
// nor for erased regions.
|
||||
ty::ReLateBound(..) | ty::ReErased => {
|
||||
return Ok(r);
|
||||
}
|
||||
|
||||
ty::ReError(_) => {
|
||||
return Ok(r);
|
||||
}
|
||||
|
||||
ty::RePlaceholder(..)
|
||||
| ty::ReVar(..)
|
||||
| ty::ReStatic
|
||||
| ty::ReEarlyBound(..)
|
||||
| ty::ReFree(..) => {
|
||||
// see common code below
|
||||
}
|
||||
}
|
||||
|
||||
// If we are in an invariant context, we can re-use the region
|
||||
// as is, unless it happens to be in some universe that we
|
||||
// can't name. (In the case of a region *variable*, we could
|
||||
// use it if we promoted it into our universe, but we don't
|
||||
// bother.)
|
||||
if let ty::Invariant = self.ambient_variance {
|
||||
let r_universe = self.infcx.universe_of_region(r);
|
||||
if self.for_universe.can_name(r_universe) {
|
||||
return Ok(r);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This is non-ideal because we don't give a
|
||||
// very descriptive origin for this region variable.
|
||||
Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.cause.span), self.for_universe))
|
||||
}
|
||||
|
||||
fn consts(
|
||||
&mut self,
|
||||
c: ty::Const<'tcx>,
|
||||
c2: ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>> {
|
||||
assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
|
||||
|
||||
match c.kind() {
|
||||
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let variable_table = &mut inner.const_unification_table();
|
||||
let var_value = variable_table.probe_value(vid);
|
||||
match var_value.val {
|
||||
ConstVariableValue::Known { value: u } => {
|
||||
drop(inner);
|
||||
self.relate(u, u)
|
||||
}
|
||||
ConstVariableValue::Unknown { universe } => {
|
||||
if self.for_universe.can_name(universe) {
|
||||
Ok(c)
|
||||
} else {
|
||||
let new_var_id = variable_table.new_key(ConstVarValue {
|
||||
origin: var_value.origin,
|
||||
val: ConstVariableValue::Unknown { universe: self.for_universe },
|
||||
});
|
||||
Ok(self.tcx().mk_const(new_var_id, c.ty()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
|
||||
let substs = self.relate_with_variance(
|
||||
ty::Variance::Invariant,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
substs,
|
||||
substs,
|
||||
)?;
|
||||
Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty()))
|
||||
}
|
||||
_ => relate::super_relate_consts(self, c, c),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
|
||||
/// Register obligations that must hold in order for this relation to hold
|
||||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>);
|
||||
|
@ -873,135 +499,3 @@ fn float_unification_error<'tcx>(
|
|||
let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
|
||||
TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b))
|
||||
}
|
||||
|
||||
struct ConstInferUnifier<'cx, 'tcx> {
|
||||
infcx: &'cx InferCtxt<'tcx>,
|
||||
|
||||
span: Span,
|
||||
|
||||
for_universe: ty::UniverseIndex,
|
||||
|
||||
/// The vid of the const variable that is in the process of being
|
||||
/// instantiated; if we find this within the const we are folding,
|
||||
/// that means we would have created a cyclic const.
|
||||
target_vid: ty::ConstVid<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ConstInferUnifier<'_, 'tcx> {
|
||||
type Error = TypeError<'tcx>;
|
||||
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, TypeError<'tcx>> {
|
||||
match t.kind() {
|
||||
&ty::Infer(ty::TyVar(vid)) => {
|
||||
let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid);
|
||||
let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid);
|
||||
match probe {
|
||||
TypeVariableValue::Known { value: u } => {
|
||||
debug!("ConstOccursChecker: known value {:?}", u);
|
||||
u.try_fold_with(self)
|
||||
}
|
||||
TypeVariableValue::Unknown { universe } => {
|
||||
if self.for_universe.can_name(universe) {
|
||||
return Ok(t);
|
||||
}
|
||||
|
||||
let origin =
|
||||
*self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
|
||||
let new_var_id = self
|
||||
.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.type_variables()
|
||||
.new_var(self.for_universe, origin);
|
||||
Ok(self.interner().mk_ty_var(new_var_id))
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => Ok(t),
|
||||
_ => t.try_super_fold_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn try_fold_region(
|
||||
&mut self,
|
||||
r: ty::Region<'tcx>,
|
||||
) -> Result<ty::Region<'tcx>, TypeError<'tcx>> {
|
||||
debug!("ConstInferUnifier: r={:?}", r);
|
||||
|
||||
match *r {
|
||||
// Never make variables for regions bound within the type itself,
|
||||
// nor for erased regions.
|
||||
ty::ReLateBound(..) | ty::ReErased | ty::ReError(_) => {
|
||||
return Ok(r);
|
||||
}
|
||||
|
||||
ty::RePlaceholder(..)
|
||||
| ty::ReVar(..)
|
||||
| ty::ReStatic
|
||||
| ty::ReEarlyBound(..)
|
||||
| ty::ReFree(..) => {
|
||||
// see common code below
|
||||
}
|
||||
}
|
||||
|
||||
let r_universe = self.infcx.universe_of_region(r);
|
||||
if self.for_universe.can_name(r_universe) {
|
||||
return Ok(r);
|
||||
} else {
|
||||
// FIXME: This is non-ideal because we don't give a
|
||||
// very descriptive origin for this region variable.
|
||||
Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe))
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, TypeError<'tcx>> {
|
||||
match c.kind() {
|
||||
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
||||
// Check if the current unification would end up
|
||||
// unifying `target_vid` with a const which contains
|
||||
// an inference variable which is unioned with `target_vid`.
|
||||
//
|
||||
// Not doing so can easily result in stack overflows.
|
||||
if self
|
||||
.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.const_unification_table()
|
||||
.unioned(self.target_vid, vid)
|
||||
{
|
||||
return Err(TypeError::CyclicConst(c));
|
||||
}
|
||||
|
||||
let var_value =
|
||||
self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid);
|
||||
match var_value.val {
|
||||
ConstVariableValue::Known { value: u } => u.try_fold_with(self),
|
||||
ConstVariableValue::Unknown { universe } => {
|
||||
if self.for_universe.can_name(universe) {
|
||||
Ok(c)
|
||||
} else {
|
||||
let new_var_id =
|
||||
self.infcx.inner.borrow_mut().const_unification_table().new_key(
|
||||
ConstVarValue {
|
||||
origin: var_value.origin,
|
||||
val: ConstVariableValue::Unknown {
|
||||
universe: self.for_universe,
|
||||
},
|
||||
},
|
||||
);
|
||||
Ok(self.interner().mk_const(new_var_id, c.ty()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => c.try_super_fold_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::infer::DefineOpaqueTypes;
|
||||
use crate::traits::PredicateObligations;
|
||||
|
||||
use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir};
|
||||
use super::combine::{CombineFields, ObligationEmittingRelation};
|
||||
use super::Subtype;
|
||||
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
|
@ -88,11 +88,11 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
|||
}
|
||||
|
||||
(&ty::Infer(TyVar(a_id)), _) => {
|
||||
self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?;
|
||||
self.fields.instantiate(b, ty::Invariant, a_id, self.a_is_expected)?;
|
||||
}
|
||||
|
||||
(_, &ty::Infer(TyVar(b_id))) => {
|
||||
self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?;
|
||||
self.fields.instantiate(a, ty::Invariant, b_id, self.a_is_expected)?;
|
||||
}
|
||||
|
||||
(
|
||||
|
|
|
@ -2723,7 +2723,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
|
|||
| (ty::Infer(ty::InferTy::TyVar(_)), _)
|
||||
| (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a),
|
||||
(ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch),
|
||||
_ => relate::super_relate_tys(self, a, b),
|
||||
_ => relate::structurally_relate_tys(self, a, b),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
479
compiler/rustc_infer/src/infer/generalize.rs
Normal file
479
compiler/rustc_infer/src/infer/generalize.rs
Normal file
|
@ -0,0 +1,479 @@
|
|||
use rustc_data_structures::sso::SsoHashMap;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, InferConst, Term, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::infer::nll_relate::TypeRelatingDelegate;
|
||||
use crate::infer::type_variable::TypeVariableValue;
|
||||
use crate::infer::{InferCtxt, RegionVariableOrigin};
|
||||
|
||||
/// Attempts to generalize `term` for the type variable `for_vid`.
|
||||
/// This checks for cycles -- that is, whether the type `term`
|
||||
/// references `for_vid`.
|
||||
pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> + Relate<'tcx>>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
delegate: &mut D,
|
||||
term: T,
|
||||
for_vid: impl Into<ty::TermVid<'tcx>>,
|
||||
ambient_variance: ty::Variance,
|
||||
) -> RelateResult<'tcx, Generalization<T>> {
|
||||
let (for_universe, root_vid) = match for_vid.into() {
|
||||
ty::TermVid::Ty(ty_vid) => (
|
||||
infcx.probe_ty_var(ty_vid).unwrap_err(),
|
||||
ty::TermVid::Ty(infcx.inner.borrow_mut().type_variables().sub_root_var(ty_vid)),
|
||||
),
|
||||
ty::TermVid::Const(ct_vid) => (
|
||||
infcx.probe_const_var(ct_vid).unwrap_err(),
|
||||
ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid)),
|
||||
),
|
||||
};
|
||||
|
||||
let mut generalizer = Generalizer {
|
||||
infcx,
|
||||
delegate,
|
||||
ambient_variance,
|
||||
root_vid,
|
||||
for_universe,
|
||||
root_term: term.into(),
|
||||
needs_wf: false,
|
||||
cache: Default::default(),
|
||||
};
|
||||
|
||||
assert!(!term.has_escaping_bound_vars());
|
||||
let value = generalizer.relate(term, term)?;
|
||||
let needs_wf = generalizer.needs_wf;
|
||||
Ok(Generalization { value, needs_wf })
|
||||
}
|
||||
|
||||
/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking
|
||||
/// in the generalizer code.
|
||||
pub trait GeneralizerDelegate<'tcx> {
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx>;
|
||||
|
||||
fn forbid_inference_vars() -> bool;
|
||||
|
||||
fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
|
||||
}
|
||||
|
||||
pub struct CombineDelegate<'cx, 'tcx> {
|
||||
pub infcx: &'cx InferCtxt<'tcx>,
|
||||
pub param_env: ty::ParamEnv<'tcx>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> {
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.param_env
|
||||
}
|
||||
|
||||
fn forbid_inference_vars() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
|
||||
// FIXME: This is non-ideal because we don't give a
|
||||
// very descriptive origin for this region variable.
|
||||
self.infcx
|
||||
.next_region_var_in_universe(RegionVariableOrigin::MiscVariable(self.span), universe)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> GeneralizerDelegate<'tcx> for T
|
||||
where
|
||||
T: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
<Self as TypeRelatingDelegate<'tcx>>::param_env(self)
|
||||
}
|
||||
|
||||
fn forbid_inference_vars() -> bool {
|
||||
<Self as TypeRelatingDelegate<'tcx>>::forbid_inference_vars()
|
||||
}
|
||||
|
||||
fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
|
||||
<Self as TypeRelatingDelegate<'tcx>>::generalize_existential(self, universe)
|
||||
}
|
||||
}
|
||||
|
||||
/// The "generalizer" is used when handling inference variables.
|
||||
///
|
||||
/// The basic strategy for handling a constraint like `?A <: B` is to
|
||||
/// apply a "generalization strategy" to the term `B` -- this replaces
|
||||
/// all the lifetimes in the term `B` with fresh inference variables.
|
||||
/// (You can read more about the strategy in this [blog post].)
|
||||
///
|
||||
/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
|
||||
/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
|
||||
/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
|
||||
/// establishes `'0: 'x` as a constraint.
|
||||
///
|
||||
/// [blog post]: https://is.gd/0hKvIr
|
||||
struct Generalizer<'me, 'tcx, D> {
|
||||
infcx: &'me InferCtxt<'tcx>,
|
||||
|
||||
/// This is used to abstract the behaviors of the three previous
|
||||
/// generalizer-like implementations (`Generalizer`, `TypeGeneralizer`,
|
||||
/// and `ConstInferUnifier`). See [`GeneralizerDelegate`] for more
|
||||
/// information.
|
||||
delegate: &'me mut D,
|
||||
|
||||
/// After we generalize this type, we are going to relate it to
|
||||
/// some other type. What will be the variance at this point?
|
||||
ambient_variance: ty::Variance,
|
||||
|
||||
/// The vid of the type variable that is in the process of being
|
||||
/// instantiated. If we find this within the value we are folding,
|
||||
/// that means we would have created a cyclic value.
|
||||
root_vid: ty::TermVid<'tcx>,
|
||||
|
||||
/// The universe of the type variable that is in the process of being
|
||||
/// instantiated. If we find anything that this universe cannot name,
|
||||
/// we reject the relation.
|
||||
for_universe: ty::UniverseIndex,
|
||||
|
||||
/// The root term (const or type) we're generalizing. Used for cycle errors.
|
||||
root_term: Term<'tcx>,
|
||||
|
||||
cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
|
||||
|
||||
/// See the field `needs_wf` in `Generalization`.
|
||||
needs_wf: bool,
|
||||
}
|
||||
|
||||
impl<'tcx, D> Generalizer<'_, 'tcx, D> {
|
||||
/// Create an error that corresponds to the term kind in `root_term`
|
||||
fn cyclic_term_error(&self) -> TypeError<'tcx> {
|
||||
match self.root_term.unpack() {
|
||||
ty::TermKind::Ty(ty) => TypeError::CyclicTy(ty),
|
||||
ty::TermKind::Const(ct) => TypeError::CyclicConst(ct),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, D> TypeRelation<'tcx> for Generalizer<'_, 'tcx, D>
|
||||
where
|
||||
D: GeneralizerDelegate<'tcx>,
|
||||
{
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.delegate.param_env()
|
||||
}
|
||||
|
||||
fn tag(&self) -> &'static str {
|
||||
"Generalizer"
|
||||
}
|
||||
|
||||
fn a_is_expected(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn relate_item_substs(
|
||||
&mut self,
|
||||
item_def_id: DefId,
|
||||
a_subst: ty::SubstsRef<'tcx>,
|
||||
b_subst: ty::SubstsRef<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::SubstsRef<'tcx>> {
|
||||
if self.ambient_variance == ty::Variance::Invariant {
|
||||
// Avoid fetching the variance if we are in an invariant
|
||||
// context; no need, and it can induce dependency cycles
|
||||
// (e.g., #41849).
|
||||
relate::relate_substs(self, a_subst, b_subst)
|
||||
} else {
|
||||
let tcx = self.tcx();
|
||||
let opt_variances = tcx.variances_of(item_def_id);
|
||||
relate::relate_substs_with_variances(
|
||||
self,
|
||||
item_def_id,
|
||||
opt_variances,
|
||||
a_subst,
|
||||
b_subst,
|
||||
true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, variance, b), ret)]
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
let old_ambient_variance = self.ambient_variance;
|
||||
self.ambient_variance = self.ambient_variance.xform(variance);
|
||||
debug!(?self.ambient_variance, "new ambient variance");
|
||||
let r = self.relate(a, b)?;
|
||||
self.ambient_variance = old_ambient_variance;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, t2), ret)]
|
||||
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
|
||||
|
||||
if let Some(&result) = self.cache.get(&t) {
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
// 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.
|
||||
let g = match *t.kind() {
|
||||
ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_))
|
||||
if D::forbid_inference_vars() =>
|
||||
{
|
||||
bug!("unexpected inference variable encountered in NLL generalization: {t}");
|
||||
}
|
||||
|
||||
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||
bug!("unexpected infer type: {t}")
|
||||
}
|
||||
|
||||
ty::Infer(ty::TyVar(vid)) => {
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let vid = inner.type_variables().root_var(vid);
|
||||
let sub_vid = inner.type_variables().sub_root_var(vid);
|
||||
|
||||
if ty::TermVid::Ty(sub_vid) == self.root_vid {
|
||||
// If sub-roots are equal, then `root_vid` and
|
||||
// `vid` are related via subtyping.
|
||||
Err(self.cyclic_term_error())
|
||||
} else {
|
||||
let probe = inner.type_variables().probe(vid);
|
||||
match probe {
|
||||
TypeVariableValue::Known { value: u } => {
|
||||
drop(inner);
|
||||
self.relate(u, u)
|
||||
}
|
||||
TypeVariableValue::Unknown { universe } => {
|
||||
match self.ambient_variance {
|
||||
// Invariant: no need to make a fresh type variable
|
||||
// if we can name the universe.
|
||||
ty::Invariant => {
|
||||
if self.for_universe.can_name(universe) {
|
||||
return Ok(t);
|
||||
}
|
||||
}
|
||||
|
||||
// Bivariant: make a fresh var, but we
|
||||
// may need a WF predicate. See
|
||||
// comment on `needs_wf` field for
|
||||
// more info.
|
||||
ty::Bivariant => self.needs_wf = true,
|
||||
|
||||
// Co/contravariant: this will be
|
||||
// sufficiently constrained later on.
|
||||
ty::Covariant | ty::Contravariant => (),
|
||||
}
|
||||
|
||||
let origin = *inner.type_variables().var_origin(vid);
|
||||
let new_var_id =
|
||||
inner.type_variables().new_var(self.for_universe, origin);
|
||||
let u = self.tcx().mk_ty_var(new_var_id);
|
||||
|
||||
// Record that we replaced `vid` with `new_var_id` as part of a generalization
|
||||
// operation. This is needed to detect cyclic types. To see why, see the
|
||||
// docs in the `type_variables` module.
|
||||
inner.type_variables().sub(vid, new_var_id);
|
||||
debug!("replacing original vid={:?} with new={:?}", vid, u);
|
||||
Ok(u)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
|
||||
// No matter what mode we are in,
|
||||
// integer/floating-point types must be equal to be
|
||||
// relatable.
|
||||
Ok(t)
|
||||
}
|
||||
|
||||
ty::Placeholder(placeholder) => {
|
||||
if self.for_universe.can_name(placeholder.universe) {
|
||||
Ok(t)
|
||||
} else {
|
||||
debug!(
|
||||
"root universe {:?} cannot name placeholder in universe {:?}",
|
||||
self.for_universe, placeholder.universe
|
||||
);
|
||||
Err(TypeError::Mismatch)
|
||||
}
|
||||
}
|
||||
|
||||
_ => relate::structurally_relate_tys(self, t, t),
|
||||
}?;
|
||||
|
||||
self.cache.insert(t, g);
|
||||
Ok(g)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, r2), ret)]
|
||||
fn regions(
|
||||
&mut self,
|
||||
r: ty::Region<'tcx>,
|
||||
r2: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
|
||||
|
||||
match *r {
|
||||
// Never make variables for regions bound within the type itself,
|
||||
// nor for erased regions.
|
||||
ty::ReLateBound(..) | ty::ReErased => {
|
||||
return Ok(r);
|
||||
}
|
||||
|
||||
// It doesn't really matter for correctness if we generalize ReError,
|
||||
// since we're already on a doomed compilation path.
|
||||
ty::ReError(_) => {
|
||||
return Ok(r);
|
||||
}
|
||||
|
||||
ty::RePlaceholder(..)
|
||||
| ty::ReVar(..)
|
||||
| ty::ReStatic
|
||||
| ty::ReEarlyBound(..)
|
||||
| ty::ReFree(..) => {
|
||||
// see common code below
|
||||
}
|
||||
}
|
||||
|
||||
// If we are in an invariant context, we can re-use the region
|
||||
// as is, unless it happens to be in some universe that we
|
||||
// can't name.
|
||||
if let ty::Invariant = self.ambient_variance {
|
||||
let r_universe = self.infcx.universe_of_region(r);
|
||||
if self.for_universe.can_name(r_universe) {
|
||||
return Ok(r);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self.delegate.generalize_region(self.for_universe))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, c2), ret)]
|
||||
fn consts(
|
||||
&mut self,
|
||||
c: ty::Const<'tcx>,
|
||||
c2: ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>> {
|
||||
assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
|
||||
|
||||
match c.kind() {
|
||||
ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
|
||||
bug!("unexpected inference variable encountered in NLL generalization: {:?}", c);
|
||||
}
|
||||
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
||||
// If root const vids are equal, then `root_vid` and
|
||||
// `vid` are related and we'd be inferring an infinitely
|
||||
// deep const.
|
||||
if ty::TermVid::Const(
|
||||
self.infcx.inner.borrow_mut().const_unification_table().find(vid),
|
||||
) == self.root_vid
|
||||
{
|
||||
return Err(self.cyclic_term_error());
|
||||
}
|
||||
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let variable_table = &mut inner.const_unification_table();
|
||||
let var_value = variable_table.probe_value(vid);
|
||||
match var_value.val {
|
||||
ConstVariableValue::Known { value: u } => {
|
||||
drop(inner);
|
||||
self.relate(u, u)
|
||||
}
|
||||
ConstVariableValue::Unknown { universe } => {
|
||||
if self.for_universe.can_name(universe) {
|
||||
Ok(c)
|
||||
} else {
|
||||
let new_var_id = variable_table.new_key(ConstVarValue {
|
||||
origin: var_value.origin,
|
||||
val: ConstVariableValue::Unknown { universe: self.for_universe },
|
||||
});
|
||||
Ok(self.tcx().mk_const(new_var_id, c.ty()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIXME: remove this branch once `structurally_relate_consts` is fully
|
||||
// structural.
|
||||
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
|
||||
let substs = self.relate_with_variance(
|
||||
ty::Variance::Invariant,
|
||||
ty::VarianceDiagInfo::default(),
|
||||
substs,
|
||||
substs,
|
||||
)?;
|
||||
Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty()))
|
||||
}
|
||||
ty::ConstKind::Placeholder(placeholder) => {
|
||||
if self.for_universe.can_name(placeholder.universe) {
|
||||
Ok(c)
|
||||
} else {
|
||||
debug!(
|
||||
"root universe {:?} cannot name placeholder in universe {:?}",
|
||||
self.for_universe, placeholder.universe
|
||||
);
|
||||
Err(TypeError::Mismatch)
|
||||
}
|
||||
}
|
||||
_ => relate::structurally_relate_consts(self, c, c),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn binders<T>(
|
||||
&mut self,
|
||||
a: ty::Binder<'tcx, T>,
|
||||
_: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
let result = self.relate(a.skip_binder(), a.skip_binder())?;
|
||||
Ok(a.rebind(result))
|
||||
}
|
||||
}
|
||||
|
||||
/// Result from a generalization operation. This includes
|
||||
/// not only the generalized type, but also a bool flag
|
||||
/// indicating whether further WF checks are needed.
|
||||
#[derive(Debug)]
|
||||
pub struct Generalization<T> {
|
||||
pub value: T,
|
||||
|
||||
/// If true, then the generalized type may not be well-formed,
|
||||
/// even if the source type is well-formed, so we should add an
|
||||
/// additional check to enforce that it is. This arises in
|
||||
/// particular around 'bivariant' type parameters that are only
|
||||
/// constrained by a where-clause. As an example, imagine a type:
|
||||
///
|
||||
/// struct Foo<A, B> where A: Iterator<Item = B> {
|
||||
/// data: A
|
||||
/// }
|
||||
///
|
||||
/// here, `A` will be covariant, but `B` is
|
||||
/// unconstrained. However, whatever it is, for `Foo` to be WF, it
|
||||
/// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`,
|
||||
/// then after generalization we will wind up with a type like
|
||||
/// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C,
|
||||
/// ?D>` (or `>:`), we will wind up with the requirement that `?A
|
||||
/// <: ?C`, but no particular relationship between `?B` and `?D`
|
||||
/// (after all, we do not know the variance of the normalized form
|
||||
/// of `A::Item` with respect to `A`). If we do nothing else, this
|
||||
/// may mean that `?D` goes unconstrained (as in #41677). So, in
|
||||
/// this scenario where we create a new type variable in a
|
||||
/// bivariant context, we set the `needs_wf` flag to true. This
|
||||
/// will force the calling code to check that `WF(Foo<?C, ?D>)`
|
||||
/// holds, which in turn implies that `?C::Item == ?D`. So once
|
||||
/// `?C` is constrained, that should suffice to restrict `?D`.
|
||||
pub needs_wf: bool,
|
||||
}
|
|
@ -58,6 +58,7 @@ pub mod error_reporting;
|
|||
pub mod free_regions;
|
||||
mod freshen;
|
||||
mod fudge;
|
||||
mod generalize;
|
||||
mod glb;
|
||||
mod higher_ranked;
|
||||
pub mod lattice;
|
||||
|
|
|
@ -21,21 +21,20 @@
|
|||
//! thing we relate in chalk are basically domain goals and their
|
||||
//! constituents)
|
||||
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::{ConstVarValue, ConstVariableValue};
|
||||
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::fold::FnMutDelegate;
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::combine::ObligationEmittingRelation;
|
||||
use crate::infer::combine::ObligationEmittingRelation;
|
||||
use crate::infer::generalize::{self, Generalization};
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
|
||||
pub struct TypeRelating<'me, 'tcx, D>
|
||||
where
|
||||
|
@ -198,7 +197,7 @@ where
|
|||
_ => (),
|
||||
}
|
||||
|
||||
let generalized_ty = self.generalize_value(value_ty, vid)?;
|
||||
let generalized_ty = self.generalize(value_ty, vid)?;
|
||||
debug!("relate_ty_var: generalized_ty = {:?}", generalized_ty);
|
||||
|
||||
if D::forbid_inference_vars() {
|
||||
|
@ -217,26 +216,15 @@ where
|
|||
result
|
||||
}
|
||||
|
||||
fn generalize_value<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
value: T,
|
||||
for_vid: ty::TyVid,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
let universe = self.infcx.probe_ty_var(for_vid).unwrap_err();
|
||||
|
||||
if value.has_escaping_bound_vars() {
|
||||
bug!("trying to instantiate {for_vid:?} with escaping bound vars: {value:?}");
|
||||
}
|
||||
|
||||
let mut generalizer = TypeGeneralizer {
|
||||
infcx: self.infcx,
|
||||
delegate: &mut self.delegate,
|
||||
ambient_variance: self.ambient_variance,
|
||||
for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid),
|
||||
universe,
|
||||
};
|
||||
|
||||
generalizer.relate(value, value)
|
||||
fn generalize(&mut self, ty: Ty<'tcx>, for_vid: ty::TyVid) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
let Generalization { value: ty, needs_wf: _ } = generalize::generalize(
|
||||
self.infcx,
|
||||
&mut self.delegate,
|
||||
ty,
|
||||
for_vid,
|
||||
self.ambient_variance,
|
||||
)?;
|
||||
Ok(ty)
|
||||
}
|
||||
|
||||
fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
|
@ -716,235 +704,3 @@ where
|
|||
})]);
|
||||
}
|
||||
}
|
||||
|
||||
/// The "type generalizer" is used when handling inference variables.
|
||||
///
|
||||
/// The basic strategy for handling a constraint like `?A <: B` is to
|
||||
/// apply a "generalization strategy" to the type `B` -- this replaces
|
||||
/// all the lifetimes in the type `B` with fresh inference
|
||||
/// variables. (You can read more about the strategy in this [blog
|
||||
/// post].)
|
||||
///
|
||||
/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
|
||||
/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
|
||||
/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
|
||||
/// establishes `'0: 'x` as a constraint.
|
||||
///
|
||||
/// [blog post]: https://is.gd/0hKvIr
|
||||
struct TypeGeneralizer<'me, 'tcx, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
infcx: &'me InferCtxt<'tcx>,
|
||||
|
||||
delegate: &'me mut D,
|
||||
|
||||
/// After we generalize this type, we are going to relate it to
|
||||
/// some other type. What will be the variance at this point?
|
||||
ambient_variance: ty::Variance,
|
||||
|
||||
/// The vid of the type variable that is in the process of being
|
||||
/// instantiated. If we find this within the value we are folding,
|
||||
/// that means we would have created a cyclic value.
|
||||
for_vid_sub_root: ty::TyVid,
|
||||
|
||||
/// The universe of the type variable that is in the process of being
|
||||
/// instantiated. If we find anything that this universe cannot name,
|
||||
/// we reject the relation.
|
||||
universe: ty::UniverseIndex,
|
||||
}
|
||||
|
||||
impl<'tcx, D> TypeRelation<'tcx> for TypeGeneralizer<'_, 'tcx, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
self.delegate.param_env()
|
||||
}
|
||||
|
||||
fn tag(&self) -> &'static str {
|
||||
"nll::generalizer"
|
||||
}
|
||||
|
||||
fn a_is_expected(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
variance: ty::Variance,
|
||||
_info: ty::VarianceDiagInfo<'tcx>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
debug!(
|
||||
"TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
|
||||
variance, a, b
|
||||
);
|
||||
|
||||
let old_ambient_variance = self.ambient_variance;
|
||||
self.ambient_variance = self.ambient_variance.xform(variance);
|
||||
|
||||
debug!(
|
||||
"TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
|
||||
self.ambient_variance
|
||||
);
|
||||
|
||||
let r = self.relate(a, b)?;
|
||||
|
||||
self.ambient_variance = old_ambient_variance;
|
||||
|
||||
debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
use crate::infer::type_variable::TypeVariableValue;
|
||||
|
||||
debug!("TypeGeneralizer::tys(a={:?})", a);
|
||||
|
||||
match *a.kind() {
|
||||
ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_))
|
||||
if D::forbid_inference_vars() =>
|
||||
{
|
||||
bug!("unexpected inference variable encountered in NLL generalization: {:?}", a);
|
||||
}
|
||||
|
||||
ty::Infer(ty::TyVar(vid)) => {
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let variables = &mut inner.type_variables();
|
||||
let vid = variables.root_var(vid);
|
||||
let sub_vid = variables.sub_root_var(vid);
|
||||
if sub_vid == self.for_vid_sub_root {
|
||||
// If sub-roots are equal, then `for_vid` and
|
||||
// `vid` are related via subtyping.
|
||||
debug!("TypeGeneralizer::tys: occurs check failed");
|
||||
Err(TypeError::Mismatch)
|
||||
} else {
|
||||
match variables.probe(vid) {
|
||||
TypeVariableValue::Known { value: u } => {
|
||||
drop(inner);
|
||||
self.relate(u, u)
|
||||
}
|
||||
TypeVariableValue::Unknown { universe: _universe } => {
|
||||
if self.ambient_variance == ty::Bivariant {
|
||||
// FIXME: we may need a WF predicate (related to #54105).
|
||||
}
|
||||
|
||||
let origin = *variables.var_origin(vid);
|
||||
|
||||
// Replacing with a new variable in the universe `self.universe`,
|
||||
// it will be unified later with the original type variable in
|
||||
// the universe `_universe`.
|
||||
let new_var_id = variables.new_var(self.universe, origin);
|
||||
|
||||
let u = self.tcx().mk_ty_var(new_var_id);
|
||||
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
|
||||
Ok(u)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
|
||||
// No matter what mode we are in,
|
||||
// integer/floating-point types must be equal to be
|
||||
// relatable.
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
ty::Placeholder(placeholder) => {
|
||||
if self.universe.cannot_name(placeholder.universe) {
|
||||
debug!(
|
||||
"TypeGeneralizer::tys: root universe {:?} cannot name\
|
||||
placeholder in universe {:?}",
|
||||
self.universe, placeholder.universe
|
||||
);
|
||||
Err(TypeError::Mismatch)
|
||||
} else {
|
||||
Ok(a)
|
||||
}
|
||||
}
|
||||
|
||||
_ => relate::super_relate_tys(self, a, a),
|
||||
}
|
||||
}
|
||||
|
||||
fn regions(
|
||||
&mut self,
|
||||
a: ty::Region<'tcx>,
|
||||
_: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
debug!("TypeGeneralizer::regions(a={:?})", a);
|
||||
|
||||
if let ty::ReLateBound(..) = *a {
|
||||
return Ok(a);
|
||||
}
|
||||
|
||||
// For now, we just always create a fresh region variable to
|
||||
// replace all the regions in the source type. In the main
|
||||
// type checker, we special case the case where the ambient
|
||||
// variance is `Invariant` and try to avoid creating a fresh
|
||||
// region variable, but since this comes up so much less in
|
||||
// NLL (only when users use `_` etc) it is much less
|
||||
// important.
|
||||
//
|
||||
// As an aside, since these new variables are created in
|
||||
// `self.universe` universe, this also serves to enforce the
|
||||
// universe scoping rules.
|
||||
//
|
||||
// FIXME(#54105) -- if the ambient variance is bivariant,
|
||||
// though, we may however need to check well-formedness or
|
||||
// risk a problem like #41677 again.
|
||||
let replacement_region_vid = self.delegate.generalize_existential(self.universe);
|
||||
|
||||
Ok(replacement_region_vid)
|
||||
}
|
||||
|
||||
fn consts(
|
||||
&mut self,
|
||||
a: ty::Const<'tcx>,
|
||||
_: ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>> {
|
||||
match a.kind() {
|
||||
ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
|
||||
bug!("unexpected inference variable encountered in NLL generalization: {:?}", a);
|
||||
}
|
||||
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let variable_table = &mut inner.const_unification_table();
|
||||
let var_value = variable_table.probe_value(vid);
|
||||
match var_value.val.known() {
|
||||
Some(u) => self.relate(u, u),
|
||||
None => {
|
||||
let new_var_id = variable_table.new_key(ConstVarValue {
|
||||
origin: var_value.origin,
|
||||
val: ConstVariableValue::Unknown { universe: self.universe },
|
||||
});
|
||||
Ok(self.tcx().mk_const(new_var_id, a.ty()))
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(a),
|
||||
_ => relate::super_relate_consts(self, a, a),
|
||||
}
|
||||
}
|
||||
|
||||
fn binders<T>(
|
||||
&mut self,
|
||||
a: ty::Binder<'tcx, T>,
|
||||
_: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
debug!("TypeGeneralizer::binders(a={:?})", a);
|
||||
let result = self.relate(a.skip_binder(), a.skip_binder())?;
|
||||
Ok(a.rebind(result))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,7 +187,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
|
|||
} else if pattern == value {
|
||||
Ok(pattern)
|
||||
} else {
|
||||
relate::super_relate_tys(self, pattern, value)
|
||||
relate::structurally_relate_tys(self, pattern, value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
|
|||
if pattern == value {
|
||||
Ok(pattern)
|
||||
} else {
|
||||
relate::super_relate_consts(self, pattern, value)
|
||||
relate::structurally_relate_consts(self, pattern, value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::combine::{CombineFields, RelationDir};
|
||||
use super::combine::CombineFields;
|
||||
use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin};
|
||||
|
||||
use crate::traits::{Obligation, PredicateObligations};
|
||||
|
@ -108,11 +108,11 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
|||
Ok(a)
|
||||
}
|
||||
(&ty::Infer(TyVar(a_id)), _) => {
|
||||
self.fields.instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?;
|
||||
self.fields.instantiate(b, ty::Contravariant, a_id, !self.a_is_expected)?;
|
||||
Ok(a)
|
||||
}
|
||||
(_, &ty::Infer(TyVar(b_id))) => {
|
||||
self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?;
|
||||
self.fields.instantiate(a, ty::Covariant, b_id, self.a_is_expected)?;
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
|
|||
|
||||
(&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(self.tcx().ty_error(guar)),
|
||||
|
||||
_ => relate::super_relate_tys(self, a, b),
|
||||
_ => relate::structurally_relate_tys(self, a, b),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
relate::super_relate_consts(self, a, b)
|
||||
relate::structurally_relate_consts(self, a, b)
|
||||
}
|
||||
|
||||
fn binders<T>(
|
||||
|
|
|
@ -1072,6 +1072,24 @@ impl ParamTerm {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum TermVid<'tcx> {
|
||||
Ty(ty::TyVid),
|
||||
Const(ty::ConstVid<'tcx>),
|
||||
}
|
||||
|
||||
impl From<ty::TyVid> for TermVid<'_> {
|
||||
fn from(value: ty::TyVid) -> Self {
|
||||
TermVid::Ty(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> From<ty::ConstVid<'tcx>> for TermVid<'tcx> {
|
||||
fn from(value: ty::ConstVid<'tcx>) -> Self {
|
||||
TermVid::Const(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// This kind of predicate has no *direct* correspondent in the
|
||||
/// syntax, but it roughly corresponds to the syntactic forms:
|
||||
///
|
||||
|
|
|
@ -388,24 +388,24 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The main "type relation" routine. Note that this does not handle
|
||||
/// inference artifacts, so you should filter those out before calling
|
||||
/// it.
|
||||
pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
||||
/// Relates `a` and `b` structurally, calling the relation for all nested values.
|
||||
/// Any semantic equality, e.g. of projections, and inference variables have to be
|
||||
/// handled by the caller.
|
||||
pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
let tcx = relation.tcx();
|
||||
debug!("super_relate_tys: a={:?} b={:?}", a, b);
|
||||
debug!("structurally_relate_tys: a={:?} b={:?}", a, b);
|
||||
match (a.kind(), b.kind()) {
|
||||
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
|
||||
// The caller should handle these cases!
|
||||
bug!("var types encountered in super_relate_tys")
|
||||
bug!("var types encountered in structurally_relate_tys")
|
||||
}
|
||||
|
||||
(ty::Bound(..), _) | (_, ty::Bound(..)) => {
|
||||
bug!("bound types encountered in super_relate_tys")
|
||||
bug!("bound types encountered in structurally_relate_tys")
|
||||
}
|
||||
|
||||
(&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(tcx.ty_error(guar)),
|
||||
|
@ -575,15 +575,18 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||
}
|
||||
}
|
||||
|
||||
/// 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<'tcx, R: TypeRelation<'tcx>>(
|
||||
/// Relates `a` and `b` structurally, calling the relation for all nested values.
|
||||
/// Any semantic equality, e.g. of unevaluated consts, and inference variables have
|
||||
/// to be handled by the caller.
|
||||
///
|
||||
/// FIXME: This is not totally structual, which probably should be fixed.
|
||||
/// See the HACKs below.
|
||||
pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
mut a: ty::Const<'tcx>,
|
||||
mut b: ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>> {
|
||||
debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
|
||||
debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
|
||||
let tcx = relation.tcx();
|
||||
|
||||
// HACK(const_generics): We still need to eagerly evaluate consts when
|
||||
|
@ -602,7 +605,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
|
|||
b = tcx.expand_abstract_consts(b);
|
||||
}
|
||||
|
||||
debug!("{}.super_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b);
|
||||
debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b);
|
||||
|
||||
// Currently, the values that can be unified are primitive types,
|
||||
// and those that derive both `PartialEq` and `Eq`, corresponding
|
||||
|
@ -610,7 +613,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
|
|||
let is_match = match (a.kind(), b.kind()) {
|
||||
(ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
|
||||
// The caller should handle these cases!
|
||||
bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
|
||||
bug!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b)
|
||||
}
|
||||
|
||||
(ty::ConstKind::Error(_), _) => return Ok(a),
|
||||
|
|
18
tests/ui/traits/non_lifetime_binders/universe-error1.rs
Normal file
18
tests/ui/traits/non_lifetime_binders/universe-error1.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
#![feature(non_lifetime_binders)]
|
||||
//~^ WARN the feature `non_lifetime_binders` is incomplete
|
||||
|
||||
trait Other<U: ?Sized> {}
|
||||
|
||||
impl<U: ?Sized> Other<U> for U {}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn foo<U: ?Sized>()
|
||||
where
|
||||
for<T> T: Other<U> {}
|
||||
|
||||
fn bar() {
|
||||
foo::<_>();
|
||||
//~^ ERROR the trait bound `T: Other<_>` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
27
tests/ui/traits/non_lifetime_binders/universe-error1.stderr
Normal file
27
tests/ui/traits/non_lifetime_binders/universe-error1.stderr
Normal file
|
@ -0,0 +1,27 @@
|
|||
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/universe-error1.rs:1:12
|
||||
|
|
||||
LL | #![feature(non_lifetime_binders)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0277]: the trait bound `T: Other<_>` is not satisfied
|
||||
--> $DIR/universe-error1.rs:14:11
|
||||
|
|
||||
LL | foo::<_>();
|
||||
| ^ the trait `Other<_>` is not implemented for `T`
|
||||
|
|
||||
note: required by a bound in `foo`
|
||||
--> $DIR/universe-error1.rs:11:15
|
||||
|
|
||||
LL | fn foo<U: ?Sized>()
|
||||
| --- required by a bound in this function
|
||||
LL | where
|
||||
LL | for<T> T: Other<U> {}
|
||||
| ^^^^^^^^ required by this bound in `foo`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue