1use std::mem;
23use rustc_data_structures::sso::SsoHashMap;
4use rustc_data_structures::stack::ensure_sufficient_stack;
5use rustc_hir::def_id::DefId;
6use rustc_middle::bug;
7use rustc_middle::ty::error::TypeError;
8use rustc_middle::ty::{
9self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
10TypeVisitableExt, TypeVisitor, TypingMode,
11};
12use rustc_span::Span;
13use tracing::{debug, instrument, warn};
1415use super::{
16PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
17};
18use crate::infer::type_variable::TypeVariableValue;
19use crate::infer::unify_key::ConstVariableValue;
20use crate::infer::{InferCtxt, RegionVariableOrigin, relate};
2122#[derive(#[automatically_derived]
impl ::core::marker::Copy for TermVid { }Copy, #[automatically_derived]
impl ::core::clone::Clone for TermVid {
#[inline]
fn clone(&self) -> TermVid {
let _: ::core::clone::AssertParamIsClone<ty::TyVid>;
let _: ::core::clone::AssertParamIsClone<ty::ConstVid>;
*self
}
}Clone, #[automatically_derived]
impl ::core::cmp::Eq for TermVid {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<ty::TyVid>;
let _: ::core::cmp::AssertParamIsEq<ty::ConstVid>;
}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialEq for TermVid {
#[inline]
fn eq(&self, other: &TermVid) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(TermVid::Ty(__self_0), TermVid::Ty(__arg1_0)) =>
__self_0 == __arg1_0,
(TermVid::Const(__self_0), TermVid::Const(__arg1_0)) =>
__self_0 == __arg1_0,
_ => unsafe { ::core::intrinsics::unreachable() }
}
}
}PartialEq, #[automatically_derived]
impl ::core::fmt::Debug for TermVid {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
TermVid::Ty(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Ty",
&__self_0),
TermVid::Const(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Const",
&__self_0),
}
}
}Debug)]
23enum TermVid {
24 Ty(ty::TyVid),
25 Const(ty::ConstVid),
26}
2728impl From<ty::TyVid> for TermVid {
29fn from(value: ty::TyVid) -> Self {
30 TermVid::Ty(value)
31 }
32}
3334impl From<ty::ConstVid> for TermVid {
35fn from(value: ty::ConstVid) -> Self {
36 TermVid::Const(value)
37 }
38}
3940impl<'tcx> InferCtxt<'tcx> {
41/// The idea is that we should ensure that the type variable `target_vid`
42 /// is equal to, a subtype of, or a supertype of `source_ty`.
43 ///
44 /// For this, we will instantiate `target_vid` with a *generalized* version
45 /// of `source_ty`. Generalization introduces other inference variables wherever
46 /// subtyping could occur. This also does the occurs checks, detecting whether
47 /// instantiating `target_vid` would result in a cyclic type. We eagerly error
48 /// in this case.
49 ///
50 /// This is *not* expected to be used anywhere except for an implementation of
51 /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all
52 /// other usecases (i.e. setting the value of a type var).
53#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("instantiate_ty_var",
"rustc_infer::infer::relate::generalize",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/generalize.rs"),
::tracing_core::__macro_support::Option::Some(53u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
::tracing_core::field::FieldSet::new(&["target_is_expected",
"target_vid", "instantiation_variance", "source_ty"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&target_is_expected
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&target_vid)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&instantiation_variance)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&source_ty)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: RelateResult<'tcx, ()> = loop {};
return __tracing_attr_fake_return;
}
{
if true {
if !self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown()
{
::core::panicking::panic("assertion failed: self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown()")
};
};
let Generalization { value_may_be_infer: generalized_ty } =
self.generalize(relation.span(),
relation.structurally_relate_aliases(), target_vid,
instantiation_variance, source_ty)?;
if let &ty::Infer(ty::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);
}
if generalized_ty.is_ty_var() {
if self.next_trait_solver() {
let (lhs, rhs, direction) =
match instantiation_variance {
ty::Invariant => {
(generalized_ty.into(), source_ty.into(),
AliasRelationDirection::Equate)
}
ty::Covariant => {
(generalized_ty.into(), source_ty.into(),
AliasRelationDirection::Subtype)
}
ty::Contravariant => {
(source_ty.into(), generalized_ty.into(),
AliasRelationDirection::Subtype)
}
ty::Bivariant => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("bivariant generalization")));
}
};
relation.register_predicates([ty::PredicateKind::AliasRelate(lhs,
rhs, direction)]);
} else {
match source_ty.kind() {
&ty::Alias(ty::Projection, data) => {
relation.register_predicates([ty::ProjectionPredicate {
projection_term: data.into(),
term: generalized_ty.into(),
}]);
}
ty::Alias(ty::Inherent | ty::Free | ty::Opaque, _) => {
return Err(TypeError::CyclicTy(source_ty));
}
_ =>
::rustc_middle::util::bug::bug_fmt(format_args!("generalized `{0:?} to infer, not an alias",
source_ty)),
}
}
} else {
if target_is_expected {
relation.relate(generalized_ty, source_ty)?;
} else {
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_infer/src/infer/relate/generalize.rs:155",
"rustc_infer::infer::relate::generalize",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/generalize.rs"),
::tracing_core::__macro_support::Option::Some(155u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("flip relation")
as &dyn Value))])
});
} else { ; }
};
relation.relate(source_ty, generalized_ty)?;
}
}
Ok(())
}
}
}#[instrument(level = "debug", skip(self, relation))]54pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
55&self,
56 relation: &mut R,
57 target_is_expected: bool,
58 target_vid: ty::TyVid,
59 instantiation_variance: ty::Variance,
60 source_ty: Ty<'tcx>,
61 ) -> RelateResult<'tcx, ()> {
62debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown());
6364// Generalize `source_ty` depending on the current variance. As an example, assume
65 // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference
66 // variable.
67 //
68 // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh
69 // region/type inference variables.
70 //
71 // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and
72 // `?1 <: ?3`.
73let Generalization { value_may_be_infer: generalized_ty } = self.generalize(
74 relation.span(),
75 relation.structurally_relate_aliases(),
76 target_vid,
77 instantiation_variance,
78 source_ty,
79 )?;
8081// Constrain `b_vid` to the generalized type `generalized_ty`.
82if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() {
83self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid);
84 } else {
85self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty);
86 }
8788// Finally, relate `generalized_ty` to `source_ty`, as described in previous comment.
89 //
90 // FIXME(#16847): This code is non-ideal because all these subtype
91 // relations wind up attributed to the same spans. We need
92 // to associate causes/spans with each of the relations in
93 // the stack to get this right.
94if generalized_ty.is_ty_var() {
95// This happens for cases like `<?0 as Trait>::Assoc == ?0`.
96 // We can't instantiate `?0` here as that would result in a
97 // cyclic type. We instead delay the unification in case
98 // the alias can be normalized to something which does not
99 // mention `?0`.
100if self.next_trait_solver() {
101let (lhs, rhs, direction) = match instantiation_variance {
102 ty::Invariant => {
103 (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Equate)
104 }
105 ty::Covariant => {
106 (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Subtype)
107 }
108 ty::Contravariant => {
109 (source_ty.into(), generalized_ty.into(), AliasRelationDirection::Subtype)
110 }
111 ty::Bivariant => unreachable!("bivariant generalization"),
112 };
113114 relation.register_predicates([ty::PredicateKind::AliasRelate(lhs, rhs, direction)]);
115 } else {
116match source_ty.kind() {
117&ty::Alias(ty::Projection, data) => {
118// FIXME: This does not handle subtyping correctly, we could
119 // instead create a new inference variable `?normalized_source`, emitting
120 // `Projection(normalized_source, ?ty_normalized)` and
121 // `?normalized_source <: generalized_ty`.
122relation.register_predicates([ty::ProjectionPredicate {
123 projection_term: data.into(),
124 term: generalized_ty.into(),
125 }]);
126 }
127// The old solver only accepts projection predicates for associated types.
128ty::Alias(ty::Inherent | ty::Free | ty::Opaque, _) => {
129return Err(TypeError::CyclicTy(source_ty));
130 }
131_ => bug!("generalized `{source_ty:?} to infer, not an alias"),
132 }
133 }
134 } else {
135// NOTE: The `instantiation_variance` is not the same variance as
136 // used by the relation. When instantiating `b`, `target_is_expected`
137 // is flipped and the `instantiation_variance` is also flipped. To
138 // constrain the `generalized_ty` while using the original relation,
139 // we therefore only have to flip the arguments.
140 //
141 // ```ignore (not code)
142 // ?a rel B
143 // instantiate_ty_var(?a, B) # expected and variance not flipped
144 // B' rel B
145 // ```
146 // or
147 // ```ignore (not code)
148 // A rel ?b
149 // instantiate_ty_var(?b, A) # expected and variance flipped
150 // A rel A'
151 // ```
152if target_is_expected {
153 relation.relate(generalized_ty, source_ty)?;
154 } else {
155debug!("flip relation");
156 relation.relate(source_ty, generalized_ty)?;
157 }
158 }
159160Ok(())
161 }
162163/// Instantiates the const variable `target_vid` with the given constant.
164 ///
165 /// This also tests if the given const `ct` contains an inference variable which was previously
166 /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct`
167 /// would result in an infinite type as we continuously replace an inference variable
168 /// in `ct` with `ct` itself.
169 ///
170 /// This is especially important as unevaluated consts use their parents generics.
171 /// They therefore often contain unused args, making these errors far more likely.
172 ///
173 /// A good example of this is the following:
174 ///
175 /// ```compile_fail,E0308
176 /// #![feature(generic_const_exprs)]
177 ///
178 /// fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] {
179 /// todo!()
180 /// }
181 ///
182 /// fn main() {
183 /// let mut arr = Default::default();
184 /// arr = bind(arr);
185 /// }
186 /// ```
187 ///
188 /// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics
189 /// of `fn bind` (meaning that its args contain `N`).
190 ///
191 /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`.
192 /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`.
193 ///
194 /// As `3 + 4` contains `N` in its args, this must not succeed.
195 ///
196 /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
197#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("instantiate_const_var",
"rustc_infer::infer::relate::generalize",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/generalize.rs"),
::tracing_core::__macro_support::Option::Some(197u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
::tracing_core::field::FieldSet::new(&["target_is_expected",
"target_vid", "source_ct"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&target_is_expected
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&target_vid)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&source_ct)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: RelateResult<'tcx, ()> = loop {};
return __tracing_attr_fake_return;
}
{
let Generalization { value_may_be_infer: generalized_ct } =
self.generalize(relation.span(),
relation.structurally_relate_aliases(), target_vid,
ty::Invariant, source_ct)?;
if true {
if !!generalized_ct.is_ct_infer() {
::core::panicking::panic("assertion failed: !generalized_ct.is_ct_infer()")
};
};
self.inner.borrow_mut().const_unification_table().union_value(target_vid,
ConstVariableValue::Known { value: generalized_ct });
if target_is_expected {
relation.relate_with_variance(ty::Invariant,
ty::VarianceDiagInfo::default(), generalized_ct,
source_ct)?;
} else {
relation.relate_with_variance(ty::Invariant,
ty::VarianceDiagInfo::default(), source_ct,
generalized_ct)?;
}
Ok(())
}
}
}#[instrument(level = "debug", skip(self, relation))]198pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
199&self,
200 relation: &mut R,
201 target_is_expected: bool,
202 target_vid: ty::ConstVid,
203 source_ct: ty::Const<'tcx>,
204 ) -> RelateResult<'tcx, ()> {
205// FIXME(generic_const_exprs): Occurs check failures for unevaluated
206 // constants and generic expressions are not yet handled correctly.
207let Generalization { value_may_be_infer: generalized_ct } = self.generalize(
208 relation.span(),
209 relation.structurally_relate_aliases(),
210 target_vid,
211 ty::Invariant,
212 source_ct,
213 )?;
214215debug_assert!(!generalized_ct.is_ct_infer());
216217self.inner
218 .borrow_mut()
219 .const_unification_table()
220 .union_value(target_vid, ConstVariableValue::Known { value: generalized_ct });
221222// Make sure that the order is correct when relating the
223 // generalized const and the source.
224if target_is_expected {
225 relation.relate_with_variance(
226 ty::Invariant,
227 ty::VarianceDiagInfo::default(),
228 generalized_ct,
229 source_ct,
230 )?;
231 } else {
232 relation.relate_with_variance(
233 ty::Invariant,
234 ty::VarianceDiagInfo::default(),
235 source_ct,
236 generalized_ct,
237 )?;
238 }
239240Ok(())
241 }
242243/// Attempts to generalize `source_term` for the type variable `target_vid`.
244 /// This checks for cycles -- that is, whether `source_term` references `target_vid`.
245fn generalize<T: Into<Term<'tcx>> + Relate<TyCtxt<'tcx>>>(
246&self,
247 span: Span,
248 structurally_relate_aliases: StructurallyRelateAliases,
249 target_vid: impl Into<TermVid>,
250 ambient_variance: ty::Variance,
251 source_term: T,
252 ) -> RelateResult<'tcx, Generalization<T>> {
253if !!source_term.has_escaping_bound_vars() {
::core::panicking::panic("assertion failed: !source_term.has_escaping_bound_vars()")
};assert!(!source_term.has_escaping_bound_vars());
254let (for_universe, root_vid) = match target_vid.into() {
255 TermVid::Ty(ty_vid) => {
256 (self.probe_ty_var(ty_vid).unwrap_err(), TermVid::Ty(self.root_var(ty_vid)))
257 }
258 TermVid::Const(ct_vid) => (
259self.probe_const_var(ct_vid).unwrap_err(),
260 TermVid::Const(self.inner.borrow_mut().const_unification_table().find(ct_vid).vid),
261 ),
262 };
263264let mut generalizer = Generalizer {
265 infcx: self,
266span,
267structurally_relate_aliases,
268root_vid,
269for_universe,
270 root_term: source_term.into(),
271ambient_variance,
272 in_alias: false,
273 cache: Default::default(),
274 };
275276let value_may_be_infer = generalizer.relate(source_term, source_term)?;
277Ok(Generalization { value_may_be_infer })
278 }
279}
280281/// Finds the max universe present
282struct MaxUniverse {
283 max_universe: ty::UniverseIndex,
284}
285286impl MaxUniverse {
287fn new() -> Self {
288MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
289 }
290291fn max_universe(self) -> ty::UniverseIndex {
292self.max_universe
293 }
294}
295296impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxUniverse {
297fn visit_ty(&mut self, t: Ty<'tcx>) {
298if let ty::Placeholder(placeholder) = t.kind() {
299self.max_universe = self.max_universe.max(placeholder.universe);
300 }
301302t.super_visit_with(self)
303 }
304305fn visit_const(&mut self, c: ty::Const<'tcx>) {
306if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
307self.max_universe = self.max_universe.max(placeholder.universe);
308 }
309310c.super_visit_with(self)
311 }
312313fn visit_region(&mut self, r: ty::Region<'tcx>) {
314if let ty::RePlaceholder(placeholder) = r.kind() {
315self.max_universe = self.max_universe.max(placeholder.universe);
316 }
317 }
318}
319320/// The "generalizer" is used when handling inference variables.
321///
322/// The basic strategy for handling a constraint like `?A <: B` is to
323/// apply a "generalization strategy" to the term `B` -- this replaces
324/// all the lifetimes in the term `B` with fresh inference variables.
325/// (You can read more about the strategy in this [blog post].)
326///
327/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
328/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
329/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
330/// establishes `'0: 'x` as a constraint.
331///
332/// [blog post]: https://is.gd/0hKvIr
333struct Generalizer<'me, 'tcx> {
334 infcx: &'me InferCtxt<'tcx>,
335336 span: Span,
337338/// Whether aliases should be related structurally. If not, we have to
339 /// be careful when generalizing aliases.
340structurally_relate_aliases: StructurallyRelateAliases,
341342/// The vid of the type variable that is in the process of being
343 /// instantiated. If we find this within the value we are folding,
344 /// that means we would have created a cyclic value.
345root_vid: TermVid,
346347/// The universe of the type variable that is in the process of being
348 /// instantiated. If we find anything that this universe cannot name,
349 /// we reject the relation.
350for_universe: ty::UniverseIndex,
351352/// The root term (const or type) we're generalizing. Used for cycle errors.
353root_term: Term<'tcx>,
354355/// After we generalize this type, we are going to relate it to
356 /// some other type. What will be the variance at this point?
357ambient_variance: ty::Variance,
358359/// This is set once we're generalizing the arguments of an alias.
360 ///
361 /// This is necessary to correctly handle
362 /// `<T as Bar<<?0 as Foo>::Assoc>::Assoc == ?0`. This equality can
363 /// hold by either normalizing the outer or the inner associated type.
364in_alias: bool,
365366 cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>,
367}
368369impl<'tcx> Generalizer<'_, 'tcx> {
370/// Create an error that corresponds to the term kind in `root_term`
371fn cyclic_term_error(&self) -> TypeError<'tcx> {
372match self.root_term.kind() {
373 ty::TermKind::Ty(ty) => TypeError::CyclicTy(ty),
374 ty::TermKind::Const(ct) => TypeError::CyclicConst(ct),
375 }
376 }
377378/// Create a new type variable in the universe of the target when
379 /// generalizing an alias.
380fn next_ty_var_for_alias(&self) -> Ty<'tcx> {
381self.infcx.next_ty_var_in_universe(self.span, self.for_universe)
382 }
383384/// An occurs check failure inside of an alias does not mean
385 /// that the types definitely don't unify. We may be able
386 /// to normalize the alias after all.
387 ///
388 /// We handle this by lazily equating the alias and generalizing
389 /// it to an inference variable. In the new solver, we always
390 /// generalize to an infer var unless the alias contains escaping
391 /// bound variables.
392 ///
393 /// Correctly handling aliases with escaping bound variables is
394 /// difficult and currently incomplete in two opposite ways:
395 /// - if we get an occurs check failure in the alias, replace it with a new infer var.
396 /// This causes us to later emit an alias-relate goal and is incomplete in case the
397 /// alias normalizes to type containing one of the bound variables.
398 /// - if the alias contains an inference variable not nameable by `for_universe`, we
399 /// continue generalizing the alias. This ends up pulling down the universe of the
400 /// inference variable and is incomplete in case the alias would normalize to a type
401 /// which does not mention that inference variable.
402fn generalize_alias_ty(
403&mut self,
404 alias: ty::AliasTy<'tcx>,
405 ) -> Result<Ty<'tcx>, TypeError<'tcx>> {
406// We do not eagerly replace aliases with inference variables if they have
407 // escaping bound vars, see the method comment for details. However, when we
408 // are inside of an alias with escaping bound vars replacing nested aliases
409 // with inference variables can cause incorrect ambiguity.
410 //
411 // cc trait-system-refactor-initiative#110
412if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias {
413return Ok(self.next_ty_var_for_alias());
414 }
415416let is_nested_alias = mem::replace(&mut self.in_alias, true);
417let result = match self.relate(alias, alias) {
418Ok(alias) => Ok(alias.to_ty(self.cx())),
419Err(e) => {
420if is_nested_alias {
421return Err(e);
422 } else {
423let mut visitor = MaxUniverse::new();
424alias.visit_with(&mut visitor);
425let infer_replacement_is_complete =
426self.for_universe.can_name(visitor.max_universe())
427 && !alias.has_escaping_bound_vars();
428if !infer_replacement_is_complete {
429{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_infer/src/infer/relate/generalize.rs:429",
"rustc_infer::infer::relate::generalize",
::tracing::Level::WARN,
::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/generalize.rs"),
::tracing_core::__macro_support::Option::Some(429u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::WARN <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::WARN <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("may incompletely handle alias type: {0:?}",
alias) as &dyn Value))])
});
} else { ; }
};warn!("may incompletely handle alias type: {alias:?}");
430 }
431432{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_infer/src/infer/relate/generalize.rs:432",
"rustc_infer::infer::relate::generalize",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/relate/generalize.rs"),
::tracing_core::__macro_support::Option::Some(432u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("generalization failure in alias")
as &dyn Value))])
});
} else { ; }
};debug!("generalization failure in alias");
433Ok(self.next_ty_var_for_alias())
434 }
435 }
436 };
437self.in_alias = is_nested_alias;
438result439 }
440}
441442impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
443fn cx(&self) -> TyCtxt<'tcx> {
444self.infcx.tcx
445 }
446447fn relate_ty_args(
448&mut self,
449 a_ty: Ty<'tcx>,
450_: Ty<'tcx>,
451 def_id: DefId,
452 a_args: ty::GenericArgsRef<'tcx>,
453 b_args: ty::GenericArgsRef<'tcx>,
454 mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
455 ) -> RelateResult<'tcx, Ty<'tcx>> {
456let args = if self.ambient_variance == ty::Invariant {
457// Avoid fetching the variance if we are in an invariant
458 // context; no need, and it can induce dependency cycles
459 // (e.g., #41849).
460relate::relate_args_invariantly(self, a_args, b_args)
461 } else {
462let tcx = self.cx();
463let variances = tcx.variances_of(def_id);
464 relate::relate_args_with_variances(self, variances, a_args, b_args)
465 }?;
466if args == a_args { Ok(a_ty) } else { Ok(mk(args)) }
467 }
468469x;#[instrument(level = "debug", skip(self, variance, b), ret)]470fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
471&mut self,
472 variance: ty::Variance,
473 _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
474 a: T,
475 b: T,
476 ) -> RelateResult<'tcx, T> {
477let old_ambient_variance = self.ambient_variance;
478self.ambient_variance = self.ambient_variance.xform(variance);
479debug!(?self.ambient_variance, "new ambient variance");
480// Recursive calls to `relate` can overflow the stack. For example a deeper version of
481 // `ui/associated-consts/issue-93775.rs`.
482let r = ensure_sufficient_stack(|| self.relate(a, b));
483self.ambient_variance = old_ambient_variance;
484 r
485 }
486487x;#[instrument(level = "debug", skip(self, t2), ret)]488fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
489assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
490491if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) {
492return Ok(result);
493 }
494495// Check to see whether the type we are generalizing references
496 // any other type variable related to `vid` via
497 // subtyping. This is basically our "occurs check", preventing
498 // us from creating infinitely sized types.
499let g = match *t.kind() {
500 ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
501bug!("unexpected infer type: {t}")
502 }
503504 ty::Infer(ty::TyVar(vid)) => {
505let mut inner = self.infcx.inner.borrow_mut();
506let vid = inner.type_variables().root_var(vid);
507if TermVid::Ty(vid) == self.root_vid {
508// If sub-roots are equal, then `root_vid` and
509 // `vid` are related via subtyping.
510Err(self.cyclic_term_error())
511 } else {
512let probe = inner.type_variables().probe(vid);
513match probe {
514 TypeVariableValue::Known { value: u } => {
515 drop(inner);
516self.relate(u, u)
517 }
518 TypeVariableValue::Unknown { universe } => {
519match self.ambient_variance {
520// Invariant: no need to make a fresh type variable
521 // if we can name the universe.
522ty::Invariant => {
523if self.for_universe.can_name(universe) {
524return Ok(t);
525 }
526 }
527528// We do need a fresh type variable otherwise.
529ty::Bivariant | ty::Covariant | ty::Contravariant => (),
530 }
531532let origin = inner.type_variables().var_origin(vid);
533let new_var_id =
534 inner.type_variables().new_var(self.for_universe, origin);
535// Record that `vid` and `new_var_id` have to be subtypes
536 // of each other. This is currently only used for diagnostics.
537 // To see why, see the docs in the `type_variables` module.
538inner.type_variables().sub_unify(vid, new_var_id);
539// If we're in the new solver and create a new inference
540 // variable inside of an alias we eagerly constrain that
541 // inference variable to prevent unexpected ambiguity errors.
542 //
543 // This is incomplete as it pulls down the universe of the
544 // original inference variable, even though the alias could
545 // normalize to a type which does not refer to that type at
546 // all. I don't expect this to cause unexpected errors in
547 // practice.
548 //
549 // We only need to do so for type and const variables, as
550 // region variables do not impact normalization, and will get
551 // correctly constrained by `AliasRelate` later on.
552 //
553 // cc trait-system-refactor-initiative#108
554if self.infcx.next_trait_solver()
555 && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
556 && self.in_alias
557 {
558 inner.type_variables().equate(vid, new_var_id);
559 }
560561debug!("replacing original vid={:?} with new={:?}", vid, new_var_id);
562Ok(Ty::new_var(self.cx(), new_var_id))
563 }
564 }
565 }
566 }
567568 ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
569// No matter what mode we are in,
570 // integer/floating-point types must be equal to be
571 // relatable.
572Ok(t)
573 }
574575 ty::Placeholder(placeholder) => {
576if self.for_universe.can_name(placeholder.universe) {
577Ok(t)
578 } else {
579debug!(
580"root universe {:?} cannot name placeholder in universe {:?}",
581self.for_universe, placeholder.universe
582 );
583Err(TypeError::Mismatch)
584 }
585 }
586587 ty::Alias(_, data) => match self.structurally_relate_aliases {
588 StructurallyRelateAliases::No => self.generalize_alias_ty(data),
589 StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t),
590 },
591592_ => relate::structurally_relate_tys(self, t, t),
593 }?;
594595self.cache.insert((t, self.ambient_variance, self.in_alias), g);
596Ok(g)
597 }
598599x;#[instrument(level = "debug", skip(self, r2), ret)]600fn regions(
601&mut self,
602 r: ty::Region<'tcx>,
603 r2: ty::Region<'tcx>,
604 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
605assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
606607match r.kind() {
608// Never make variables for regions bound within the type itself,
609 // nor for erased regions.
610ty::ReBound(..) | ty::ReErased => {
611return Ok(r);
612 }
613614// It doesn't really matter for correctness if we generalize ReError,
615 // since we're already on a doomed compilation path.
616ty::ReError(_) => {
617return Ok(r);
618 }
619620 ty::RePlaceholder(..)
621 | ty::ReVar(..)
622 | ty::ReStatic
623 | ty::ReEarlyParam(..)
624 | ty::ReLateParam(..) => {
625// see common code below
626}
627 }
628629// If we are in an invariant context, we can re-use the region
630 // as is, unless it happens to be in some universe that we
631 // can't name.
632if let ty::Invariant = self.ambient_variance {
633let r_universe = self.infcx.universe_of_region(r);
634if self.for_universe.can_name(r_universe) {
635return Ok(r);
636 }
637 }
638639Ok(self
640.infcx
641 .next_region_var_in_universe(RegionVariableOrigin::Misc(self.span), self.for_universe))
642 }
643644x;#[instrument(level = "debug", skip(self, c2), ret)]645fn consts(
646&mut self,
647 c: ty::Const<'tcx>,
648 c2: ty::Const<'tcx>,
649 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
650assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
651652match c.kind() {
653 ty::ConstKind::Infer(InferConst::Var(vid)) => {
654// If root const vids are equal, then `root_vid` and
655 // `vid` are related and we'd be inferring an infinitely
656 // deep const.
657if TermVid::Const(
658self.infcx.inner.borrow_mut().const_unification_table().find(vid).vid,
659 ) == self.root_vid
660 {
661return Err(self.cyclic_term_error());
662 }
663664let mut inner = self.infcx.inner.borrow_mut();
665let variable_table = &mut inner.const_unification_table();
666match variable_table.probe_value(vid) {
667 ConstVariableValue::Known { value: u } => {
668 drop(inner);
669self.relate(u, u)
670 }
671 ConstVariableValue::Unknown { origin, universe } => {
672if self.for_universe.can_name(universe) {
673Ok(c)
674 } else {
675let new_var_id = variable_table
676 .new_key(ConstVariableValue::Unknown {
677 origin,
678 universe: self.for_universe,
679 })
680 .vid;
681682// See the comment for type inference variables
683 // for more details.
684if self.infcx.next_trait_solver()
685 && !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
686 && self.in_alias
687 {
688 variable_table.union(vid, new_var_id);
689 }
690Ok(ty::Const::new_var(self.cx(), new_var_id))
691 }
692 }
693 }
694 }
695// FIXME: Unevaluated constants are also not rigid, so the current
696 // approach of always relating them structurally is incomplete.
697 //
698 // FIXME: remove this branch once `structurally_relate_consts` is fully
699 // structural.
700ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
701let args = self.relate_with_variance(
702 ty::Invariant,
703 ty::VarianceDiagInfo::default(),
704 args,
705 args,
706 )?;
707Ok(ty::Const::new_unevaluated(self.cx(), ty::UnevaluatedConst { def, args }))
708 }
709 ty::ConstKind::Placeholder(placeholder) => {
710if self.for_universe.can_name(placeholder.universe) {
711Ok(c)
712 } else {
713debug!(
714"root universe {:?} cannot name placeholder in universe {:?}",
715self.for_universe, placeholder.universe
716 );
717Err(TypeError::Mismatch)
718 }
719 }
720_ => relate::structurally_relate_consts(self, c, c),
721 }
722 }
723724x;#[instrument(level = "debug", skip(self), ret)]725fn binders<T>(
726&mut self,
727 a: ty::Binder<'tcx, T>,
728_: ty::Binder<'tcx, T>,
729 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
730where
731T: Relate<TyCtxt<'tcx>>,
732 {
733let result = self.relate(a.skip_binder(), a.skip_binder())?;
734Ok(a.rebind(result))
735 }
736}
737738/// Result from a generalization operation. This includes
739/// not only the generalized type, but also a bool flag
740/// indicating whether further WF checks are needed.
741#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for Generalization<T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Generalization", "value_may_be_infer", &&self.value_may_be_infer)
}
}Debug)]
742struct Generalization<T> {
743/// When generalizing `<?0 as Trait>::Assoc` or
744 /// `<T as Bar<<?0 as Foo>::Assoc>>::Assoc`
745 /// for `?0` generalization returns an inference
746 /// variable.
747 ///
748 /// This has to be handled with care as it can
749 /// otherwise very easily result in infinite
750 /// recursion.
751pub value_may_be_infer: T,
752}