Skip to content

Commit f50591f

Browse files
committed
normalize at the start of generalize if we can
1 parent 7a123e8 commit f50591f

2 files changed

Lines changed: 63 additions & 27 deletions

File tree

compiler/rustc_infer/src/infer/relate/generalize.rs

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,31 @@ impl From<ty::ConstVid> for TermVid {
3838
}
3939

4040
impl<'tcx> InferCtxt<'tcx> {
41+
fn check_generalized_alias_normalizes_to_tyvar<R: PredicateEmittingRelation<Self>>(
42+
&self,
43+
relation: &mut R,
44+
source_ty: Ty<'tcx>,
45+
) -> Option<Ty<'tcx>> {
46+
if !self.next_trait_solver()
47+
|| matches!(relation.structurally_relate_aliases(), StructurallyRelateAliases::Yes)
48+
{
49+
return None;
50+
}
51+
52+
// If we get an alias
53+
let ty::Alias(_, alias) = source_ty.kind() else {
54+
return None;
55+
};
56+
57+
if alias.has_escaping_bound_vars() {
58+
return None;
59+
}
60+
61+
let normalized_alias = relation.try_eagerly_normalize_alias(*alias);
62+
63+
normalized_alias.is_ty_var().then_some(normalized_alias)
64+
}
65+
4166
/// The idea is that we should ensure that the type variable `target_vid`
4267
/// is equal to, a subtype of, or a supertype of `source_ty`.
4368
///
@@ -51,7 +76,7 @@ impl<'tcx> InferCtxt<'tcx> {
5176
/// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all
5277
/// other usecases (i.e. setting the value of a type var).
5378
#[instrument(level = "debug", skip(self, relation))]
54-
pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
79+
pub fn instantiate_ty_var<R: PredicateEmittingRelation<Self>>(
5580
&self,
5681
relation: &mut R,
5782
target_is_expected: bool,
@@ -61,38 +86,42 @@ impl<'tcx> InferCtxt<'tcx> {
6186
) -> RelateResult<'tcx, ()> {
6287
debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown());
6388

64-
// 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`.
73-
let 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-
&mut |alias| relation.try_eagerly_normalize_alias(alias),
80-
)?;
81-
82-
// Constrain `b_vid` to the generalized type `generalized_ty`.
83-
if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() {
84-
self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid);
85-
} else {
86-
self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty);
87-
}
89+
let generalized_ty =
90+
match self.check_generalized_alias_normalizes_to_tyvar(relation, source_ty) {
91+
Some(tyvar) => tyvar,
92+
None => {
93+
// Generalize `source_ty` depending on the current variance. As an example, assume
94+
// `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference
95+
// variable.
96+
//
97+
// Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh
98+
// region/type inference variables.
99+
//
100+
// We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and
101+
// `?1 <: ?3`.
102+
let generalizer = self.generalize(
103+
relation.span(),
104+
relation.structurally_relate_aliases(),
105+
target_vid,
106+
instantiation_variance,
107+
source_ty,
108+
&mut |alias| relation.try_eagerly_normalize_alias(alias),
109+
)?;
110+
111+
generalizer.value_may_be_infer
112+
}
113+
};
88114

89115
// Finally, relate `generalized_ty` to `source_ty`, as described in previous comment.
90116
//
91117
// FIXME(#16847): This code is non-ideal because all these subtype
92118
// relations wind up attributed to the same spans. We need
93119
// to associate causes/spans with each of the relations in
94120
// the stack to get this right.
95-
if generalized_ty.is_ty_var() {
121+
if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() {
122+
// Constrain `b_vid` to the generalized type variable.
123+
self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid);
124+
96125
// This happens for cases like `<?0 as Trait>::Assoc == ?0`.
97126
// We can't instantiate `?0` here as that would result in a
98127
// cyclic type. We instead delay the unification in case
@@ -133,6 +162,9 @@ impl<'tcx> InferCtxt<'tcx> {
133162
}
134163
}
135164
} else {
165+
// Constrain `b_vid` to the generalized type `generalized_ty`.
166+
self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty);
167+
136168
// NOTE: The `instantiation_variance` is not the same variance as
137169
// used by the relation. When instantiating `b`, `target_is_expected`
138170
// is flipped and the `instantiation_variance` is also flipped. To

compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,11 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
177177
cache: Default::default(),
178178
};
179179
let param_env = param_env.fold_with(&mut env_canonicalizer);
180-
debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
180+
debug_assert!(
181+
env_canonicalizer.sub_root_lookup_table.is_empty(),
182+
"{:?}",
183+
env_canonicalizer.sub_root_lookup_table
184+
);
181185
(
182186
param_env,
183187
env_canonicalizer.variables,

0 commit comments

Comments
 (0)