Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/next_solver/infer/relate/generalize.rs')
-rw-r--r--crates/hir-ty/src/next_solver/infer/relate/generalize.rs720
1 files changed, 720 insertions, 0 deletions
diff --git a/crates/hir-ty/src/next_solver/infer/relate/generalize.rs b/crates/hir-ty/src/next_solver/infer/relate/generalize.rs
new file mode 100644
index 0000000000..7e2735db3b
--- /dev/null
+++ b/crates/hir-ty/src/next_solver/infer/relate/generalize.rs
@@ -0,0 +1,720 @@
+//! Type generation code.
+
+use std::mem;
+
+use rustc_hash::FxHashMap;
+use rustc_type_ir::error::TypeError;
+use rustc_type_ir::inherent::{Const as _, IntoKind, Ty as _};
+use rustc_type_ir::relate::VarianceDiagInfo;
+use rustc_type_ir::{
+ AliasRelationDirection, AliasTyKind, ConstVid, InferConst, InferCtxtLike, InferTy, RegionKind,
+ TermKind, TyVid, UniverseIndex, Variance,
+};
+use rustc_type_ir::{Interner, TypeVisitable, TypeVisitableExt};
+use tracing::{debug, instrument, warn};
+
+use super::{
+ PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
+};
+use crate::next_solver::infer::type_variable::TypeVariableValue;
+use crate::next_solver::infer::unify_key::ConstVariableValue;
+use crate::next_solver::infer::{InferCtxt, relate};
+use crate::next_solver::util::MaxUniverse;
+use crate::next_solver::{
+ AliasTy, Binder, ClauseKind, Const, ConstKind, DbInterner, GenericArgs, PredicateKind,
+ ProjectionPredicate, Region, SolverDefId, Term, TermVid, Ty, TyKind, TypingMode,
+ UnevaluatedConst,
+};
+
+impl<'db> InferCtxt<'db> {
+ /// The idea is that we should ensure that the type variable `target_vid`
+ /// is equal to, a subtype of, or a supertype of `source_ty`.
+ ///
+ /// For this, we will instantiate `target_vid` with a *generalized* version
+ /// of `source_ty`. Generalization introduces other inference variables wherever
+ /// subtyping could occur. This also does the occurs checks, detecting whether
+ /// instantiating `target_vid` would result in a cyclic type. We eagerly error
+ /// in this case.
+ ///
+ /// This is *not* expected to be used anywhere except for an implementation of
+ /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all
+ /// other usecases (i.e. setting the value of a type var).
+ #[instrument(level = "debug", skip(self, relation))]
+ pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'db>>>(
+ &self,
+ relation: &mut R,
+ target_is_expected: bool,
+ target_vid: TyVid,
+ instantiation_variance: Variance,
+ source_ty: Ty<'db>,
+ ) -> RelateResult<'db, ()> {
+ debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown());
+
+ // Generalize `source_ty` depending on the current variance. As an example, assume
+ // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference
+ // variable.
+ //
+ // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh
+ // region/type inference variables.
+ //
+ // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and
+ // `?1 <: ?3`.
+ let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self
+ .generalize(
+ relation.structurally_relate_aliases(),
+ target_vid,
+ instantiation_variance,
+ source_ty,
+ )?;
+
+ // Constrain `b_vid` to the generalized type `generalized_ty`.
+ if let TyKind::Infer(InferTy::TyVar(generalized_vid)) = generalized_ty.kind() {
+ self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid);
+ } else {
+ self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty);
+ }
+
+ // See the comment on `Generalization::has_unconstrained_ty_var`.
+ if has_unconstrained_ty_var {
+ relation.register_predicates([ClauseKind::WellFormed(generalized_ty.into())]);
+ }
+
+ // Finally, relate `generalized_ty` to `source_ty`, as described in previous comment.
+ //
+ // FIXME(#16847): This code is non-ideal because all these subtype
+ // 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.
+ if generalized_ty.is_ty_var() {
+ // This happens for cases like `<?0 as Trait>::Assoc == ?0`.
+ // We can't instantiate `?0` here as that would result in a
+ // cyclic type. We instead delay the unification in case
+ // the alias can be normalized to something which does not
+ // mention `?0`.
+ let (lhs, rhs, direction) = match instantiation_variance {
+ Variance::Invariant => {
+ (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Equate)
+ }
+ Variance::Covariant => {
+ (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Subtype)
+ }
+ Variance::Contravariant => {
+ (source_ty.into(), generalized_ty.into(), AliasRelationDirection::Subtype)
+ }
+ Variance::Bivariant => unreachable!("bivariant generalization"),
+ };
+
+ relation.register_predicates([PredicateKind::AliasRelate(lhs, rhs, direction)]);
+ } else {
+ // NOTE: The `instantiation_variance` is not the same variance as
+ // used by the relation. When instantiating `b`, `target_is_expected`
+ // is flipped and the `instantiation_variance` is also flipped. To
+ // constrain the `generalized_ty` while using the original relation,
+ // we therefore only have to flip the arguments.
+ //
+ // ```ignore (not code)
+ // ?a rel B
+ // instantiate_ty_var(?a, B) # expected and variance not flipped
+ // B' rel B
+ // ```
+ // or
+ // ```ignore (not code)
+ // A rel ?b
+ // instantiate_ty_var(?b, A) # expected and variance flipped
+ // A rel A'
+ // ```
+ if target_is_expected {
+ relation.relate(generalized_ty, source_ty)?;
+ } else {
+ debug!("flip relation");
+ relation.relate(source_ty, generalized_ty)?;
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Instantiates the const variable `target_vid` with the given constant.
+ ///
+ /// This also tests if the given const `ct` contains an inference variable which was previously
+ /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct`
+ /// would result in an infinite type as we continuously replace an inference variable
+ /// in `ct` with `ct` itself.
+ ///
+ /// This is especially important as unevaluated consts use their parents generics.
+ /// They therefore often contain unused args, making these errors far more likely.
+ ///
+ /// A good example of this is the following:
+ ///
+ /// ```compile_fail,E0308
+ /// #![feature(generic_const_exprs)]
+ ///
+ /// fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] {
+ /// todo!()
+ /// }
+ ///
+ /// fn main() {
+ /// let mut arr = Default::default();
+ /// arr = bind(arr);
+ /// }
+ /// ```
+ ///
+ /// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics
+ /// of `fn bind` (meaning that its args contain `N`).
+ ///
+ /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`.
+ /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`.
+ ///
+ /// As `3 + 4` contains `N` in its args, this must not succeed.
+ ///
+ /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
+ #[instrument(level = "debug", skip(self, relation))]
+ pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'db>>>(
+ &self,
+ relation: &mut R,
+ target_is_expected: bool,
+ target_vid: ConstVid,
+ source_ct: Const<'db>,
+ ) -> RelateResult<'db, ()> {
+ // FIXME(generic_const_exprs): Occurs check failures for unevaluated
+ // constants and generic expressions are not yet handled correctly.
+ let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = self
+ .generalize(
+ relation.structurally_relate_aliases(),
+ target_vid,
+ Variance::Invariant,
+ source_ct,
+ )?;
+
+ debug_assert!(!generalized_ct.is_ct_infer());
+ if has_unconstrained_ty_var {
+ panic!("unconstrained ty var when generalizing `{source_ct:?}`");
+ }
+
+ self.inner
+ .borrow_mut()
+ .const_unification_table()
+ .union_value(target_vid, ConstVariableValue::Known { value: generalized_ct });
+
+ // Make sure that the order is correct when relating the
+ // generalized const and the source.
+ if target_is_expected {
+ relation.relate_with_variance(
+ Variance::Invariant,
+ VarianceDiagInfo::default(),
+ generalized_ct,
+ source_ct,
+ )?;
+ } else {
+ relation.relate_with_variance(
+ Variance::Invariant,
+ VarianceDiagInfo::default(),
+ source_ct,
+ generalized_ct,
+ )?;
+ }
+
+ Ok(())
+ }
+
+ /// Attempts to generalize `source_term` for the type variable `target_vid`.
+ /// This checks for cycles -- that is, whether `source_term` references `target_vid`.
+ fn generalize<T: Into<Term<'db>> + Relate<DbInterner<'db>>>(
+ &self,
+ structurally_relate_aliases: StructurallyRelateAliases,
+ target_vid: impl Into<TermVid>,
+ ambient_variance: Variance,
+ source_term: T,
+ ) -> RelateResult<'db, Generalization<T>> {
+ assert!(!source_term.clone().has_escaping_bound_vars());
+ let (for_universe, root_vid) = match target_vid.into() {
+ TermVid::Ty(ty_vid) => {
+ (self.probe_ty_var(ty_vid).unwrap_err(), TermVid::Ty(self.root_var(ty_vid)))
+ }
+ TermVid::Const(ct_vid) => (
+ self.probe_const_var(ct_vid).unwrap_err(),
+ TermVid::Const(self.inner.borrow_mut().const_unification_table().find(ct_vid).vid),
+ ),
+ };
+
+ let mut generalizer = Generalizer {
+ infcx: self,
+ structurally_relate_aliases,
+ root_vid,
+ for_universe,
+ root_term: source_term.into(),
+ ambient_variance,
+ in_alias: false,
+ cache: Default::default(),
+ has_unconstrained_ty_var: false,
+ };
+
+ let value_may_be_infer = generalizer.relate(source_term, source_term)?;
+ let has_unconstrained_ty_var = generalizer.has_unconstrained_ty_var;
+ Ok(Generalization { value_may_be_infer, has_unconstrained_ty_var })
+ }
+}
+
+/// 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, 'db> {
+ infcx: &'me InferCtxt<'db>,
+
+ /// Whether aliases should be related structurally. If not, we have to
+ /// be careful when generalizing aliases.
+ structurally_relate_aliases: StructurallyRelateAliases,
+
+ /// 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: TermVid,
+
+ /// 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: UniverseIndex,
+
+ /// The root term (const or type) we're generalizing. Used for cycle errors.
+ root_term: Term<'db>,
+
+ /// 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: Variance,
+
+ /// This is set once we're generalizing the arguments of an alias.
+ ///
+ /// This is necessary to correctly handle
+ /// `<T as Bar<<?0 as Foo>::Assoc>::Assoc == ?0`. This equality can
+ /// hold by either normalizing the outer or the inner associated type.
+ in_alias: bool,
+
+ cache: FxHashMap<(Ty<'db>, Variance, bool), Ty<'db>>,
+
+ /// See the field `has_unconstrained_ty_var` in `Generalization`.
+ has_unconstrained_ty_var: bool,
+}
+
+impl<'db> Generalizer<'_, 'db> {
+ /// Create an error that corresponds to the term kind in `root_term`
+ fn cyclic_term_error(&self) -> TypeError<DbInterner<'db>> {
+ match self.root_term.kind() {
+ TermKind::Ty(ty) => TypeError::CyclicTy(ty),
+ TermKind::Const(ct) => TypeError::CyclicConst(ct),
+ }
+ }
+
+ /// Create a new type variable in the universe of the target when
+ /// generalizing an alias. This has to set `has_unconstrained_ty_var`
+ /// if we're currently in a bivariant context.
+ fn next_ty_var_for_alias(&mut self) -> Ty<'db> {
+ self.has_unconstrained_ty_var |= self.ambient_variance == Variance::Bivariant;
+ self.infcx.next_ty_var_in_universe(self.for_universe)
+ }
+
+ /// An occurs check failure inside of an alias does not mean
+ /// that the types definitely don't unify. We may be able
+ /// to normalize the alias after all.
+ ///
+ /// We handle this by lazily equating the alias and generalizing
+ /// it to an inference variable. In the new solver, we always
+ /// generalize to an infer var unless the alias contains escaping
+ /// bound variables.
+ ///
+ /// Correctly handling aliases with escaping bound variables is
+ /// difficult and currently incomplete in two opposite ways:
+ /// - if we get an occurs check failure in the alias, replace it with a new infer var.
+ /// This causes us to later emit an alias-relate goal and is incomplete in case the
+ /// alias normalizes to type containing one of the bound variables.
+ /// - if the alias contains an inference variable not nameable by `for_universe`, we
+ /// continue generalizing the alias. This ends up pulling down the universe of the
+ /// inference variable and is incomplete in case the alias would normalize to a type
+ /// which does not mention that inference variable.
+ fn generalize_alias_ty(
+ &mut self,
+ alias: AliasTy<'db>,
+ ) -> Result<Ty<'db>, TypeError<DbInterner<'db>>> {
+ // We do not eagerly replace aliases with inference variables if they have
+ // escaping bound vars, see the method comment for details. However, when we
+ // are inside of an alias with escaping bound vars replacing nested aliases
+ // with inference variables can cause incorrect ambiguity.
+ //
+ // cc trait-system-refactor-initiative#110
+ if !alias.has_escaping_bound_vars() && !self.in_alias {
+ return Ok(self.next_ty_var_for_alias());
+ }
+
+ let is_nested_alias = mem::replace(&mut self.in_alias, true);
+ let result = match self.relate(alias, alias) {
+ Ok(alias) => Ok(alias.to_ty(self.cx())),
+ Err(e) => {
+ if is_nested_alias {
+ return Err(e);
+ } else {
+ let mut visitor = MaxUniverse::new();
+ alias.visit_with(&mut visitor);
+ let infer_replacement_is_complete =
+ self.for_universe.can_name(visitor.max_universe())
+ && !alias.has_escaping_bound_vars();
+ if !infer_replacement_is_complete {
+ warn!("may incompletely handle alias type: {alias:?}");
+ }
+
+ debug!("generalization failure in alias");
+ Ok(self.next_ty_var_for_alias())
+ }
+ }
+ };
+ self.in_alias = is_nested_alias;
+ result
+ }
+}
+
+impl<'db> TypeRelation<DbInterner<'db>> for Generalizer<'_, 'db> {
+ fn cx(&self) -> DbInterner<'db> {
+ self.infcx.interner
+ }
+
+ fn relate_item_args(
+ &mut self,
+ item_def_id: SolverDefId,
+ a_arg: GenericArgs<'db>,
+ b_arg: GenericArgs<'db>,
+ ) -> RelateResult<'db, GenericArgs<'db>> {
+ if self.ambient_variance == 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_args_invariantly(self, a_arg, b_arg)
+ } else {
+ let tcx = self.cx();
+ let opt_variances = tcx.variances_of(item_def_id);
+ relate::relate_args_with_variances(
+ self,
+ item_def_id,
+ opt_variances,
+ a_arg,
+ b_arg,
+ false,
+ )
+ }
+ }
+
+ #[instrument(level = "debug", skip(self, variance, b), ret)]
+ fn relate_with_variance<T: Relate<DbInterner<'db>>>(
+ &mut self,
+ variance: Variance,
+ _info: VarianceDiagInfo<DbInterner<'db>>,
+ a: T,
+ b: T,
+ ) -> RelateResult<'db, T> {
+ let old_ambient_variance = self.ambient_variance;
+ self.ambient_variance = self.ambient_variance.xform(variance);
+ debug!(?self.ambient_variance, "new ambient variance");
+ // Recursive calls to `relate` can overflow the stack. For example a deeper version of
+ // `ui/associated-consts/issue-93775.rs`.
+ let r = self.relate(a, b);
+ self.ambient_variance = old_ambient_variance;
+ r
+ }
+
+ #[instrument(level = "debug", skip(self, t2), ret)]
+ fn tys(&mut self, t: Ty<'db>, t2: Ty<'db>) -> RelateResult<'db, Ty<'db>> {
+ assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
+
+ if let Some(result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) {
+ 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() {
+ TyKind::Infer(
+ InferTy::FreshTy(_) | InferTy::FreshIntTy(_) | InferTy::FreshFloatTy(_),
+ ) => {
+ panic!("unexpected infer type: {t:?}")
+ }
+
+ TyKind::Infer(InferTy::TyVar(vid)) => {
+ let mut inner = self.infcx.inner.borrow_mut();
+ let vid = inner.type_variables().root_var(vid);
+ if TermVid::Ty(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.
+ Variance::Invariant => {
+ if self.for_universe.can_name(universe) {
+ return Ok(t);
+ }
+ }
+
+ // Bivariant: make a fresh var, but remember that
+ // it is unconstrained. See the comment in
+ // `Generalization`.
+ Variance::Bivariant => self.has_unconstrained_ty_var = true,
+
+ // Co/contravariant: this will be
+ // sufficiently constrained later on.
+ Variance::Covariant | Variance::Contravariant => (),
+ }
+
+ let origin = inner.type_variables().var_origin(vid);
+ let new_var_id =
+ inner.type_variables().new_var(self.for_universe, origin);
+ // If we're in the new solver and create a new inference
+ // variable inside of an alias we eagerly constrain that
+ // inference variable to prevent unexpected ambiguity errors.
+ //
+ // This is incomplete as it pulls down the universe of the
+ // original inference variable, even though the alias could
+ // normalize to a type which does not refer to that type at
+ // all. I don't expect this to cause unexpected errors in
+ // practice.
+ //
+ // We only need to do so for type and const variables, as
+ // region variables do not impact normalization, and will get
+ // correctly constrained by `AliasRelate` later on.
+ //
+ // cc trait-system-refactor-initiative#108
+ if self.infcx.next_trait_solver()
+ && !matches!(
+ self.infcx.typing_mode_unchecked(),
+ TypingMode::Coherence
+ )
+ && self.in_alias
+ {
+ inner.type_variables().equate(vid, new_var_id);
+ }
+
+ debug!("replacing original vid={:?} with new={:?}", vid, new_var_id);
+ Ok(Ty::new_var(self.infcx.interner, new_var_id))
+ }
+ }
+ }
+ }
+
+ TyKind::Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) => {
+ // No matter what mode we are in,
+ // integer/floating-point types must be equal to be
+ // relatable.
+ Ok(t)
+ }
+
+ TyKind::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)
+ }
+ }
+
+ TyKind::Alias(_, data) => match self.structurally_relate_aliases {
+ StructurallyRelateAliases::No => self.generalize_alias_ty(data),
+ StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t),
+ },
+
+ _ => relate::structurally_relate_tys(self, t, t),
+ }?;
+
+ self.cache.insert((t, self.ambient_variance, self.in_alias), g);
+ Ok(g)
+ }
+
+ #[instrument(level = "debug", skip(self, r2), ret)]
+ fn regions(&mut self, r: Region<'db>, r2: Region<'db>) -> RelateResult<'db, Region<'db>> {
+ assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
+
+ match r.kind() {
+ // Never make variables for regions bound within the type itself,
+ // nor for erased regions.
+ RegionKind::ReBound(..) | RegionKind::ReErased => {
+ return Ok(r);
+ }
+
+ // It doesn't really matter for correctness if we generalize ReError,
+ // since we're already on a doomed compilation path.
+ RegionKind::ReError(_) => {
+ return Ok(r);
+ }
+
+ RegionKind::RePlaceholder(..)
+ | RegionKind::ReVar(..)
+ | RegionKind::ReStatic
+ | RegionKind::ReEarlyParam(..)
+ | RegionKind::ReLateParam(..) => {
+ // 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 Variance::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.infcx.next_region_var_in_universe(self.for_universe))
+ }
+
+ #[instrument(level = "debug", skip(self, c2), ret)]
+ fn consts(&mut self, c: Const<'db>, c2: Const<'db>) -> RelateResult<'db, Const<'db>> {
+ assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
+
+ match c.kind() {
+ 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 TermVid::Const(
+ self.infcx.inner.borrow_mut().const_unification_table().find(vid).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();
+ match variable_table.probe_value(vid) {
+ ConstVariableValue::Known { value: u } => {
+ drop(inner);
+ self.relate(u, u)
+ }
+ ConstVariableValue::Unknown { origin, universe } => {
+ if self.for_universe.can_name(universe) {
+ Ok(c)
+ } else {
+ let new_var_id = variable_table
+ .new_key(ConstVariableValue::Unknown {
+ origin,
+ universe: self.for_universe,
+ })
+ .vid;
+
+ // See the comment for type inference variables
+ // for more details.
+ if self.infcx.next_trait_solver()
+ && !matches!(
+ self.infcx.typing_mode_unchecked(),
+ TypingMode::Coherence
+ )
+ && self.in_alias
+ {
+ variable_table.union(vid, new_var_id);
+ }
+ Ok(Const::new_var(self.infcx.interner, new_var_id))
+ }
+ }
+ }
+ }
+ // FIXME: Unevaluated constants are also not rigid, so the current
+ // approach of always relating them structurally is incomplete.
+ //
+ // FIXME: remove this branch once `structurally_relate_consts` is fully
+ // structural.
+ ConstKind::Unevaluated(UnevaluatedConst { def, args }) => {
+ let args = self.relate_with_variance(
+ Variance::Invariant,
+ VarianceDiagInfo::default(),
+ args,
+ args,
+ )?;
+ Ok(Const::new_unevaluated(self.infcx.interner, UnevaluatedConst { def, args }))
+ }
+ 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: Binder<'db, T>,
+ _: Binder<'db, T>,
+ ) -> RelateResult<'db, Binder<'db, T>>
+ where
+ T: Relate<DbInterner<'db>>,
+ {
+ 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)]
+struct Generalization<T> {
+ /// When generalizing `<?0 as Trait>::Assoc` or
+ /// `<T as Bar<<?0 as Foo>::Assoc>>::Assoc`
+ /// for `?0` generalization returns an inference
+ /// variable.
+ ///
+ /// This has to be handled wotj care as it can
+ /// otherwise very easily result in infinite
+ /// recursion.
+ pub value_may_be_infer: T,
+
+ /// In general, we do not check whether all types which occur during
+ /// type checking are well-formed. We only check wf of user-provided types
+ /// and when actually using a type, e.g. for method calls.
+ ///
+ /// This means that when subtyping, we may end up with unconstrained
+ /// inference variables if a generalized type has bivariant parameters.
+ /// A parameter may only be bivariant if it is constrained by a projection
+ /// bound in 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 `Foo<?A, ?B> <: Foo<?C, ?D>`,
+ /// we will wind up with the requirement that `?A <: ?C`, but no particular
+ /// relationship between `?B` and `?D` (after all, these types may be completely
+ /// different). If we do nothing else, this may mean that `?D` goes unconstrained
+ /// (as in #41677). To avoid this we emit a `WellFormed` obligation in these cases.
+ pub has_unconstrained_ty_var: bool,
+}