1use std::mem;
23use rustc_data_structures::sso::SsoHashMap;
4use rustc_hir::def_id::DefId;
5use rustc_middle::bug;
6use rustc_middle::ty::error::TypeError;
7use rustc_middle::ty::{self, InferConst, Term, Ty, TyCtxt, TypeVisitableExt};
8use rustc_span::Span;
9use tracing::{debug, instrument, warn};
1011use super::{PredicateEmittingRelation, Relate, RelateResult, TypeRelation};
12use crate::infer::type_variable::TypeVariableValue;
13use crate::infer::unify_key::ConstVariableValue;
14use crate::infer::{InferCtxt, RegionVariableOrigin, relate};
1516#[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_fields_are_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)]
17enum TermVid {
18 Ty(ty::TyVid),
19 Const(ty::ConstVid),
20}
2122impl From<ty::TyVid> for TermVid {
23fn from(value: ty::TyVid) -> Self {
24 TermVid::Ty(value)
25 }
26}
2728impl From<ty::ConstVid> for TermVid {
29fn from(value: ty::ConstVid) -> Self {
30 TermVid::Const(value)
31 }
32}
3334impl<'tcx> InferCtxt<'tcx> {
35/// The idea is that we should ensure that the type variable `target_vid`
36 /// is equal to, a subtype of, or a supertype of `source_ty`.
37 ///
38 /// For this, we will instantiate `target_vid` with a *generalized* version
39 /// of `source_ty`. Generalization introduces other inference variables wherever
40 /// subtyping could occur. This also does the occurs checks, detecting whether
41 /// instantiating `target_vid` would result in a cyclic type. We eagerly error
42 /// in this case.
43 ///
44 /// This is *not* expected to be used anywhere except for an implementation of
45 /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all
46 /// other usecases (i.e. setting the value of a type var).
47#[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(47u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("target_is_expected")
}> =
::tracing::__macro_support::FieldName::new("target_is_expected");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("target_vid")
}> =
::tracing::__macro_support::FieldName::new("target_vid");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("instantiation_variance")
}> =
::tracing::__macro_support::FieldName::new("instantiation_variance");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("source_ty")
}> =
::tracing::__macro_support::FieldName::new("source_ty");
NAME.as_str()
}], ::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};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&target_is_expected
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&target_vid)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&instantiation_variance)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&source_ty)
as &dyn ::tracing::field::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()")
};
};
self.instantiate_var(relation, target_is_expected,
target_vid.into(), instantiation_variance, source_ty.into())
}
}
}#[instrument(level = "debug", skip(self, relation))]48pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
49&self,
50 relation: &mut R,
51 target_is_expected: bool,
52 target_vid: ty::TyVid,
53 instantiation_variance: ty::Variance,
54 source_ty: Ty<'tcx>,
55 ) -> RelateResult<'tcx, ()> {
56debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown());
5758self.instantiate_var(
59 relation,
60 target_is_expected,
61 target_vid.into(),
62 instantiation_variance,
63 source_ty.into(),
64 )
65 }
6667/// Instantiates the const variable `target_vid` with the given constant.
68 ///
69 /// This also tests if the given const `ct` contains an inference variable which was previously
70 /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct`
71 /// would result in an infinite type as we continuously replace an inference variable
72 /// in `ct` with `ct` itself.
73 ///
74 /// This is especially important as alias consts use their parents generics.
75 /// They therefore often contain unused args, making these errors far more likely.
76 ///
77 /// A good example of this is the following:
78 ///
79 /// ```compile_fail,E0308
80 /// #![feature(generic_const_exprs)]
81 ///
82 /// fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] {
83 /// todo!()
84 /// }
85 ///
86 /// fn main() {
87 /// let mut arr = Default::default();
88 /// arr = bind(arr);
89 /// }
90 /// ```
91 ///
92 /// Here `3 + 4` ends up as `ConstKind::Alias` which uses the generics
93 /// of `fn bind` (meaning that its args contain `N`).
94 ///
95 /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`.
96 /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`.
97 ///
98 /// As `3 + 4` contains `N` in its args, this must not succeed.
99 ///
100 /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
101#[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(101u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("target_is_expected")
}> =
::tracing::__macro_support::FieldName::new("target_is_expected");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("target_vid")
}> =
::tracing::__macro_support::FieldName::new("target_vid");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("source_ct")
}> =
::tracing::__macro_support::FieldName::new("source_ct");
NAME.as_str()
}], ::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};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&target_is_expected
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&target_vid)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&source_ct)
as &dyn ::tracing::field::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().const_unification_table().probe_value(target_vid).is_unknown()
{
::core::panicking::panic("assertion failed: self.inner.borrow_mut().const_unification_table().probe_value(target_vid).is_unknown()")
};
};
self.instantiate_var(relation, target_is_expected,
target_vid.into(), ty::Invariant, source_ct.into())
}
}
}#[instrument(level = "debug", skip(self, relation))]102pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
103&self,
104 relation: &mut R,
105 target_is_expected: bool,
106 target_vid: ty::ConstVid,
107 source_ct: ty::Const<'tcx>,
108 ) -> RelateResult<'tcx, ()> {
109// FIXME(generic_const_exprs): Occurs check failures for alias consts
110 // and generic expressions are not yet handled correctly.
111debug_assert!(
112self.inner.borrow_mut().const_unification_table().probe_value(target_vid).is_unknown()
113 );
114115self.instantiate_var(
116 relation,
117 target_is_expected,
118 target_vid.into(),
119 ty::Invariant,
120 source_ct.into(),
121 )
122 }
123124#[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_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(124u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::relate::generalize"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("target_is_expected")
}> =
::tracing::__macro_support::FieldName::new("target_is_expected");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("target_vid")
}> =
::tracing::__macro_support::FieldName::new("target_vid");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("instantiation_variance")
}> =
::tracing::__macro_support::FieldName::new("instantiation_variance");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("source_term")
}> =
::tracing::__macro_support::FieldName::new("source_term");
NAME.as_str()
}], ::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};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&target_is_expected
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&target_vid)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&instantiation_variance)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&source_term)
as &dyn ::tracing::field::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_term } =
self.generalize(relation.span(), target_vid,
instantiation_variance, source_term)?;
self.union_var_term(target_vid, generalized_term);
if generalized_term.is_infer() {
let Some(source_alias) =
source_term.to_alias_term() else {
::rustc_middle::util::bug::bug_fmt(format_args!("generalized `{0:?} to infer, not an alias",
source_term));
};
if !!self.next_trait_solver() {
{
::core::panicking::panic_fmt(format_args!("nonrigid aliases should be handled in relations, not here"));
}
};
match source_alias.kind {
ty::AliasTermKind::ProjectionTy { .. } |
ty::AliasTermKind::ProjectionConst { .. } => {
relation.register_predicates([ty::ProjectionPredicate {
projection_term: source_alias,
term: generalized_term,
}]);
}
ty::AliasTermKind::InherentTy { .. } |
ty::AliasTermKind::FreeTy { .. } |
ty::AliasTermKind::OpaqueTy { .. } => {
return Err(TypeError::CyclicTy(source_term.expect_type()));
}
ty::AliasTermKind::InherentConst { .. } |
ty::AliasTermKind::FreeConst { .. } |
ty::AliasTermKind::AnonConst { .. } => {
return Err(TypeError::CyclicConst(source_term.expect_const()));
}
}
} else {
match generalized_term.kind() {
ty::TermKind::Ty(_) => {
if target_is_expected {
relation.relate(generalized_term, source_term)?;
} 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:214",
"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(214u32),
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("flip relation")
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
relation.relate(source_term, generalized_term)?;
}
}
ty::TermKind::Const(_) => {
if target_is_expected {
relation.relate_with_variance(ty::Invariant,
ty::VarianceDiagInfo::default(), generalized_term,
source_term)?;
} else {
relation.relate_with_variance(ty::Invariant,
ty::VarianceDiagInfo::default(), source_term,
generalized_term)?;
}
}
}
}
Ok(())
}
}
}#[instrument(level = "debug", skip(self, relation))]125fn instantiate_var<R: PredicateEmittingRelation<Self>>(
126&self,
127 relation: &mut R,
128 target_is_expected: bool,
129 target_vid: TermVid,
130 instantiation_variance: ty::Variance,
131 source_term: Term<'tcx>,
132 ) -> RelateResult<'tcx, ()> {
133// Generalize `source_term` depending on the current variance. As an example, assume
134 // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference
135 // variable.
136 //
137 // Then the `generalized_term` would be `&'?2 ?3`, where `'?2` and `?3` are fresh
138 // region/type inference variables.
139 //
140 // We then relate `generalized_term <: source_term`, adding constraints like `'x: '?2` and
141 // `?1 <: ?3`.
142let Generalization { value_may_be_infer: generalized_term } =
143self.generalize(relation.span(), target_vid, instantiation_variance, source_term)?;
144145// Constrain `b_vid` to the generalized type `generalized_term`.
146self.union_var_term(target_vid, generalized_term);
147148// Finally, relate `generalized_term` to `source_term`, as described in previous comment.
149 //
150 // FIXME(#16847): This code is non-ideal because all these subtype
151 // relations wind up attributed to the same spans. We need
152 // to associate causes/spans with each of the relations in
153 // the stack to get this right.
154if generalized_term.is_infer() {
155// This happens for cases like `<?0 as Trait>::Assoc == ?0`.
156 // We can't instantiate `?0` here as that would result in a
157 // cyclic type. We instead delay the unification in case
158 // the alias can be normalized to something which does not
159 // mention `?0`.
160let Some(source_alias) = source_term.to_alias_term() else {
161bug!("generalized `{source_term:?} to infer, not an alias");
162 };
163assert!(
164 !self.next_trait_solver(),
165"nonrigid aliases should be handled in relations, not here"
166);
167match source_alias.kind {
168 ty::AliasTermKind::ProjectionTy { .. }
169 | ty::AliasTermKind::ProjectionConst { .. } => {
170// FIXME: This does not handle subtyping correctly, we could
171 // instead create a new inference variable `?normalized_source`, emitting
172 // `Projection(normalized_source, ?ty_normalized)` and
173 // `?normalized_source <: generalized_term`.
174relation.register_predicates([ty::ProjectionPredicate {
175 projection_term: source_alias,
176 term: generalized_term,
177 }]);
178 }
179// The old solver only accepts projection predicates for associated types.
180ty::AliasTermKind::InherentTy { .. }
181 | ty::AliasTermKind::FreeTy { .. }
182 | ty::AliasTermKind::OpaqueTy { .. } => {
183return Err(TypeError::CyclicTy(source_term.expect_type()));
184 }
185 ty::AliasTermKind::InherentConst { .. }
186 | ty::AliasTermKind::FreeConst { .. }
187 | ty::AliasTermKind::AnonConst { .. } => {
188return Err(TypeError::CyclicConst(source_term.expect_const()));
189 }
190 }
191 } else {
192// NOTE: The `instantiation_variance` is not the same variance as
193 // used by the relation. When instantiating `b`, `target_is_expected`
194 // is flipped and the `instantiation_variance` is also flipped. To
195 // constrain the `generalized_term` while using the original relation,
196 // we therefore only have to flip the arguments.
197 //
198 // ```ignore (not code)
199 // ?a rel B
200 // instantiate_ty_var(?a, B) # expected and variance not flipped
201 // B' rel B
202 // ```
203 // or
204 // ```ignore (not code)
205 // A rel ?b
206 // instantiate_ty_var(?b, A) # expected and variance flipped
207 // A rel A'
208 // ```
209match generalized_term.kind() {
210 ty::TermKind::Ty(_) => {
211if target_is_expected {
212 relation.relate(generalized_term, source_term)?;
213 } else {
214debug!("flip relation");
215 relation.relate(source_term, generalized_term)?;
216 }
217 }
218 ty::TermKind::Const(_) => {
219// Override consts to always be invariant
220if target_is_expected {
221 relation.relate_with_variance(
222 ty::Invariant,
223 ty::VarianceDiagInfo::default(),
224 generalized_term,
225 source_term,
226 )?;
227 } else {
228 relation.relate_with_variance(
229 ty::Invariant,
230 ty::VarianceDiagInfo::default(),
231 source_term,
232 generalized_term,
233 )?;
234 }
235 }
236 }
237 }
238239Ok(())
240 }
241242/// This is a thin wrapper around inserting into the var tables. You probably want
243 /// [`Self::instantiate_var`] instead, which calls this method.
244fn union_var_term(&self, l: TermVid, r: ty::Term<'tcx>) {
245match (l, r.kind()) {
246 (TermVid::Ty(l), ty::TermKind::Ty(r)) => {
247if let Some(r) = r.ty_vid() {
248self.inner.borrow_mut().type_variables().equate(l, r)
249 } else {
250// Ideally, we put this assert into `type_variables().instantiate()`.
251 // But we can't pass the infcx into it as the infcx is already
252 // mutably borrowed.
253if true {
if !self.try_resolve_ty_var(l).unwrap_err().can_name(ty::max_universe(self,
r)) {
::core::panicking::panic("assertion failed: self.try_resolve_ty_var(l).unwrap_err().can_name(ty::max_universe(self, r))")
};
};debug_assert!(
254self.try_resolve_ty_var(l).unwrap_err().can_name(ty::max_universe(self, r))
255 );
256self.inner.borrow_mut().type_variables().instantiate(l, r)
257 }
258 }
259 (TermVid::Const(l), ty::TermKind::Const(r)) => {
260if let Some(r) = r.ct_vid() {
261self.inner.borrow_mut().const_unification_table().union(l, r)
262 } else {
263if true {
if !self.try_resolve_const_var(l).unwrap_err().can_name(ty::max_universe(self,
r)) {
::core::panicking::panic("assertion failed: self.try_resolve_const_var(l).unwrap_err().can_name(ty::max_universe(self, r))")
};
};debug_assert!(
264self.try_resolve_const_var(l)
265 .unwrap_err()
266 .can_name(ty::max_universe(self, r))
267 );
268self.inner
269 .borrow_mut()
270 .const_unification_table()
271 .union_value(l, ConstVariableValue::Known { value: r })
272 }
273 }
274_ => ::rustc_middle::util::bug::bug_fmt(format_args!("mismatched term kinds in generalize: {0:?}, {1:?}",
l, r))bug!("mismatched term kinds in generalize: {l:?}, {r:?}"),
275 }
276 }
277278/// Attempts to generalize `source_term` for the type variable `target_vid`.
279 /// This checks for cycles -- that is, whether `source_term` references `target_vid`.
280fn generalize(
281&self,
282 span: Span,
283 target_vid: TermVid,
284 ambient_variance: ty::Variance,
285 source_term: Term<'tcx>,
286 ) -> RelateResult<'tcx, Generalization<Term<'tcx>>> {
287if !!source_term.has_escaping_bound_vars() {
::core::panicking::panic("assertion failed: !source_term.has_escaping_bound_vars()")
};assert!(!source_term.has_escaping_bound_vars());
288let (for_universe, root_vid) = match target_vid {
289 TermVid::Ty(ty_vid) => {
290 (self.try_resolve_ty_var(ty_vid).unwrap_err(), TermVid::Ty(self.root_var(ty_vid)))
291 }
292 TermVid::Const(ct_vid) => (
293self.try_resolve_const_var(ct_vid).unwrap_err(),
294 TermVid::Const(self.inner.borrow_mut().const_unification_table().find(ct_vid).vid),
295 ),
296 };
297298let mut generalizer = Generalizer {
299 infcx: self,
300span,
301root_vid,
302for_universe,
303 root_term: source_term,
304ambient_variance,
305 in_alias: false,
306 cache: Default::default(),
307 };
308309let value_may_be_infer = generalizer.relate(source_term, source_term)?;
310Ok(Generalization { value_may_be_infer })
311 }
312}
313314/// The "generalizer" is used when handling inference variables.
315///
316/// The basic strategy for handling a constraint like `?A <: B` is to
317/// apply a "generalization strategy" to the term `B` -- this replaces
318/// all the lifetimes in the term `B` with fresh inference variables.
319/// (You can read more about the strategy in this [blog post].)
320///
321/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
322/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
323/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
324/// establishes `'0: 'x` as a constraint.
325///
326/// [blog post]: https://is.gd/0hKvIr
327struct Generalizer<'me, 'tcx> {
328 infcx: &'me InferCtxt<'tcx>,
329330 span: Span,
331332/// The vid of the type variable that is in the process of being
333 /// instantiated. If we find this within the value we are folding,
334 /// that means we would have created a cyclic value.
335root_vid: TermVid,
336337/// The universe of the type variable that is in the process of being
338 /// instantiated. If we find anything that this universe cannot name,
339 /// we reject the relation.
340for_universe: ty::UniverseIndex,
341342/// The root term (const or type) we're generalizing. Used for cycle errors.
343root_term: Term<'tcx>,
344345/// After we generalize this type, we are going to relate it to
346 /// some other type. What will be the variance at this point?
347ambient_variance: ty::Variance,
348349/// This is set once we're generalizing the arguments of an alias.
350 ///
351 /// This is necessary to correctly handle
352 /// `<T as Bar<<?0 as Foo>::Assoc>::Assoc == ?0`. This equality can
353 /// hold by either normalizing the outer or the inner associated type.
354in_alias: bool,
355356 cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>,
357}
358359impl<'tcx> Generalizer<'_, 'tcx> {
360/// Create an error that corresponds to the term kind in `root_term`
361fn cyclic_term_error(&self) -> TypeError<'tcx> {
362match self.root_term.kind() {
363 ty::TermKind::Ty(ty) => TypeError::CyclicTy(ty),
364 ty::TermKind::Const(ct) => TypeError::CyclicConst(ct),
365 }
366 }
367368/// Create a new type variable in the universe of the target when
369 /// generalizing an alias.
370fn next_var_for_alias_of_kind(&self, alias: ty::AliasTerm<'tcx>) -> ty::Term<'tcx> {
371if alias.kind.is_type() {
372self.infcx.next_ty_var_in_universe(self.span, self.for_universe).into()
373 } else {
374self.infcx.next_const_var_in_universe(self.span, self.for_universe).into()
375 }
376 }
377378/// We only handle potentially normalizable aliases via this method. For rigid alias,
379 /// we always generalize structurally.
380 ///
381 /// An occurs check failure inside of an alias does not mean
382 /// that the types definitely don't unify. We may be able
383 /// to normalize the alias after all.
384 ///
385 /// We handle this by lazily equating the normalizable alias
386 /// and generalizing it to an inference variable. In the new solver,
387 /// we always generalize to an infer var unless the alias contains escaping
388 /// bound variables.
389 ///
390 /// Correctly handling aliases with escaping bound variables is
391 /// difficult and currently incomplete in two opposite ways:
392 /// - if we get an occurs check failure in the alias, replace it with a new infer var.
393 /// This causes us to later emit an alias-relate goal and is incomplete in case the
394 /// alias normalizes to type containing one of the bound variables.
395 /// - if the alias contains an inference variable not nameable by `for_universe`, we
396 /// continue generalizing the alias. This ends up pulling down the universe of the
397 /// inference variable and is incomplete in case the alias would normalize to a type
398 /// which does not mention that inference variable.
399fn generalize_alias_term(
400&mut self,
401 alias: ty::AliasTerm<'tcx>,
402 ) -> Result<Term<'tcx>, TypeError<'tcx>> {
403// We do not eagerly replace aliases with inference variables if they have
404 // escaping bound vars, see the method comment for details. However, when we
405 // are inside of an alias with escaping bound vars replacing nested aliases
406 // with inference variables can cause incorrect ambiguity.
407 //
408 // cc trait-system-refactor-initiative#110
409if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias {
410return Ok(self.next_var_for_alias_of_kind(alias));
411 }
412413let is_nested_alias = mem::replace(&mut self.in_alias, true);
414let result = match self.relate(alias, alias) {
415Ok(alias) => Ok(alias.to_term(self.cx(), ty::IsRigid::No)),
416Err(e) => {
417if is_nested_alias {
418return Err(e);
419 } else {
420let alias_max_universe = ty::max_universe_of_placeholders(self.infcx, alias);
421let infer_replacement_is_complete =
422self.for_universe.can_name(alias_max_universe)
423 && !alias.has_escaping_bound_vars();
424if !infer_replacement_is_complete {
425{
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:425",
"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(425u32),
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("may incompletely handle alias type: {0:?}",
alias) as &dyn ::tracing::field::Value))])
});
} else { ; }
};warn!("may incompletely handle alias type: {alias:?}");
426 }
427428{
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:428",
"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(428u32),
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("generalization failure in alias")
as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("generalization failure in alias");
429Ok(self.next_var_for_alias_of_kind(alias))
430 }
431 }
432 };
433self.in_alias = is_nested_alias;
434result435 }
436}
437438impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
439fn cx(&self) -> TyCtxt<'tcx> {
440self.infcx.tcx
441 }
442443fn relate_ty_args(
444&mut self,
445 a_ty: Ty<'tcx>,
446_: Ty<'tcx>,
447 def_id: DefId,
448 a_args: ty::GenericArgsRef<'tcx>,
449 b_args: ty::GenericArgsRef<'tcx>,
450 mk: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
451 ) -> RelateResult<'tcx, Ty<'tcx>> {
452let args = if self.ambient_variance == ty::Invariant {
453// Avoid fetching the variance if we are in an invariant
454 // context; no need, and it can induce dependency cycles
455 // (e.g., #41849).
456relate::relate_args_invariantly(self, a_args, b_args)
457 } else {
458let tcx = self.cx();
459let variances = tcx.variances_of(def_id);
460 relate::relate_args_with_variances(self, variances, a_args, b_args)
461 }?;
462if args == a_args { Ok(a_ty) } else { Ok(mk(args)) }
463 }
464465x;#[instrument(level = "debug", skip(self, variance, b), ret)]466fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
467&mut self,
468 variance: ty::Variance,
469 _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
470 a: T,
471 b: T,
472 ) -> RelateResult<'tcx, T> {
473let old_ambient_variance = self.ambient_variance;
474self.ambient_variance = self.ambient_variance.xform(variance);
475debug!(?self.ambient_variance, "new ambient variance");
476// Recursive calls to `relate` can overflow the stack. For example a deeper version of
477 // `ui/associated-consts/issue-93775.rs`.
478let r = self.relate(a, b);
479self.ambient_variance = old_ambient_variance;
480 r
481 }
482483x;#[instrument(level = "debug", skip(self, t2), ret)]484fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
485assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
486487if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) {
488return Ok(result);
489 }
490491// Check to see whether the type we are generalizing references
492 // any other type variable related to `vid` via
493 // subtyping. This is basically our "occurs check", preventing
494 // us from creating infinitely sized types.
495let g = match *t.kind() {
496 ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
497bug!("unexpected infer type: {t}")
498 }
499500 ty::Infer(ty::TyVar(vid)) => {
501let mut inner = self.infcx.inner.borrow_mut();
502let vid = inner.type_variables().root_var(vid);
503if TermVid::Ty(vid) == self.root_vid {
504// If sub-roots are equal, then `root_vid` and
505 // `vid` are related via subtyping.
506Err(self.cyclic_term_error())
507 } else {
508let probe = inner.type_variables().probe(vid);
509match probe {
510 TypeVariableValue::Known { value: u } => {
511 drop(inner);
512self.relate(u, u)
513 }
514 TypeVariableValue::Unknown { universe } => {
515match self.ambient_variance {
516// Invariant: no need to make a fresh type variable
517 // if we can name the universe.
518ty::Invariant => {
519if self.for_universe.can_name(universe) {
520return Ok(t);
521 }
522 }
523524// We do need a fresh type variable otherwise.
525ty::Bivariant | ty::Covariant | ty::Contravariant => (),
526 }
527528let origin = inner.type_variables().var_origin(vid);
529let new_var_id =
530 inner.type_variables().new_var(self.for_universe, origin);
531// Record that `vid` and `new_var_id` have to be subtypes
532 // of each other. This is currently only used for diagnostics.
533 // To see why, see the docs in the `type_variables` module.
534inner.type_variables().sub_unify(vid, new_var_id);
535// If we're in the new solver and create a new inference
536 // variable inside of an alias we eagerly constrain that
537 // inference variable to prevent unexpected ambiguity errors.
538 //
539 // This is incomplete as it pulls down the universe of the
540 // original inference variable, even though the alias could
541 // normalize to a type which does not refer to that type at
542 // all. I don't expect this to cause unexpected errors in
543 // practice.
544 //
545 // We only need to do so for type and const variables, as
546 // region variables do not impact normalization, and will get
547 // correctly constrained by `AliasRelate` later on.
548 //
549 // cc trait-system-refactor-initiative#108
550if self.infcx.next_trait_solver()
551 && !self.infcx.typing_mode_raw().is_coherence()
552 && self.in_alias
553 {
554 inner.type_variables().equate(vid, new_var_id);
555 }
556557debug!("replacing original vid={:?} with new={:?}", vid, new_var_id);
558Ok(Ty::new_var(self.cx(), new_var_id))
559 }
560 }
561 }
562 }
563564 ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
565// No matter what mode we are in,
566 // integer/floating-point types must be equal to be
567 // relatable.
568Ok(t)
569 }
570571 ty::Placeholder(placeholder) => {
572if self.for_universe.can_name(placeholder.universe) {
573Ok(t)
574 } else {
575debug!(
576"root universe {:?} cannot name placeholder in universe {:?}",
577self.for_universe, placeholder.universe
578 );
579Err(TypeError::Mismatch)
580 }
581 }
582583// We only need to be careful with potentially normalizeable
584 // aliases here. See `generalize_alias_term` for more information.
585ty::Alias(ty::IsRigid::No, data) => {
586self.generalize_alias_term(data.into()).map(|v| v.expect_type())
587 }
588589_ => relate::structurally_relate_tys(self, t, t),
590 }?;
591592self.cache.insert((t, self.ambient_variance, self.in_alias), g);
593Ok(g)
594 }
595596x;#[instrument(level = "debug", skip(self, r2), ret)]597fn regions(
598&mut self,
599 r: ty::Region<'tcx>,
600 r2: ty::Region<'tcx>,
601 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
602assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
603604match r.kind() {
605// Never make variables for regions bound within the type itself,
606 // nor for erased regions.
607ty::ReBound(..) | ty::ReErased => {
608return Ok(r);
609 }
610611// It doesn't really matter for correctness if we generalize ReError,
612 // since we're already on a doomed compilation path.
613ty::ReError(_) => {
614return Ok(r);
615 }
616617 ty::RePlaceholder(..)
618 | ty::ReVar(..)
619 | ty::ReStatic
620 | ty::ReEarlyParam(..)
621 | ty::ReLateParam(..) => {
622// see common code below
623}
624 }
625626// If we are in an invariant context, we can re-use the region
627 // as is, unless it happens to be in some universe that we
628 // can't name.
629if let ty::Invariant = self.ambient_variance {
630let r_universe = self.infcx.universe_of_region(r);
631if self.for_universe.can_name(r_universe) {
632return Ok(r);
633 }
634 }
635636Ok(self
637.infcx
638 .next_region_var_in_universe(RegionVariableOrigin::Misc(self.span), self.for_universe))
639 }
640641x;#[instrument(level = "debug", skip(self, c2), ret)]642fn consts(
643&mut self,
644 c: ty::Const<'tcx>,
645 c2: ty::Const<'tcx>,
646 ) -> RelateResult<'tcx, ty::Const<'tcx>> {
647let tcx = self.cx();
648assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
649650match c.kind() {
651 ty::ConstKind::Infer(InferConst::Var(vid)) => {
652// If root const vids are equal, then `root_vid` and
653 // `vid` are related and we'd be inferring an infinitely
654 // deep const.
655if TermVid::Const(
656self.infcx.inner.borrow_mut().const_unification_table().find(vid).vid,
657 ) == self.root_vid
658 {
659return Err(self.cyclic_term_error());
660 }
661662let mut inner = self.infcx.inner.borrow_mut();
663let variable_table = &mut inner.const_unification_table();
664match variable_table.probe_value(vid) {
665 ConstVariableValue::Known { value: u } => {
666 drop(inner);
667self.relate(u, u)
668 }
669 ConstVariableValue::Unknown { origin, universe } => {
670if self.for_universe.can_name(universe) {
671Ok(c)
672 } else {
673let new_var_id = variable_table
674 .new_key(ConstVariableValue::Unknown {
675 origin,
676 universe: self.for_universe,
677 })
678 .vid;
679680// See the comment for type inference variables
681 // for more details.
682if self.infcx.next_trait_solver()
683 && !self.infcx.typing_mode_raw().is_coherence()
684 && self.in_alias
685 {
686 variable_table.union(vid, new_var_id);
687 }
688Ok(ty::Const::new_var(tcx, new_var_id))
689 }
690 }
691 }
692 }
693// FIXME: Alias consts are also not rigid, so the current
694 // approach of always relating them structurally is incomplete.
695 //
696 // FIXME: replace the `else` branch with
697 // `structurally_relate_consts` once it is fully structural.
698 //
699 // We only need to be careful with potentially normalizeable
700 // aliases here. See `generalize_alias_term` for more information.
701ty::ConstKind::Alias(ty::IsRigid::No, alias_const) => {
702// Hack: Fall back to old behavior if GCE is enabled (it used to just be the Yes
703 // path), as doing this new No path breaks some GCE things. I expect GCE to be
704 // ripped out soon so this shouldn't matter soon.
705if self.infcx.next_trait_solver() || !tcx.features().generic_const_exprs() {
706self.generalize_alias_term(alias_const.into()).map(|v| v.expect_const())
707 } else {
708let ty::AliasConst { kind, args, .. } = alias_const;
709let args = self.relate_with_variance(
710 ty::Invariant,
711 ty::VarianceDiagInfo::default(),
712 args,
713 args,
714 )?;
715Ok(ty::Const::new_alias(
716 tcx,
717 ty::IsRigid::No,
718 ty::AliasConst::new(tcx, kind, args),
719 ))
720 }
721 }
722 ty::ConstKind::Placeholder(placeholder) => {
723if self.for_universe.can_name(placeholder.universe) {
724Ok(c)
725 } else {
726debug!(
727"root universe {:?} cannot name placeholder in universe {:?}",
728self.for_universe, placeholder.universe
729 );
730Err(TypeError::Mismatch)
731 }
732 }
733_ => relate::structurally_relate_consts(self, c, c),
734 }
735 }
736737x;#[instrument(level = "debug", skip(self), ret)]738fn binders<T>(
739&mut self,
740 a: ty::Binder<'tcx, T>,
741_: ty::Binder<'tcx, T>,
742 ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
743where
744T: Relate<TyCtxt<'tcx>>,
745 {
746let result = self.relate(a.skip_binder(), a.skip_binder())?;
747Ok(a.rebind(result))
748 }
749}
750751/// Result from a generalization operation. This includes
752/// not only the generalized type, but also a bool flag
753/// indicating whether further WF checks are needed.
754#[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)]
755struct Generalization<T> {
756/// When generalizing `<?0 as Trait>::Assoc` or
757 /// `<T as Bar<<?0 as Foo>::Assoc>>::Assoc`
758 /// for `?0` generalization returns an inference
759 /// variable.
760 ///
761 /// This has to be handled with care as it can
762 /// otherwise very easily result in infinite
763 /// recursion.
764pub value_may_be_infer: T,
765}