Skip to content

Commit e8e3544

Browse files
committed
try generalizing if normalization isn't a tyvar
1 parent f50591f commit e8e3544

1 file changed

Lines changed: 59 additions & 56 deletions

File tree

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

Lines changed: 59 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,6 @@ 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-
6641
/// The idea is that we should ensure that the type variable `target_vid`
6742
/// is equal to, a subtype of, or a supertype of `source_ty`.
6843
///
@@ -86,31 +61,53 @@ impl<'tcx> InferCtxt<'tcx> {
8661
) -> RelateResult<'tcx, ()> {
8762
debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown());
8863

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-
};
64+
let generalized_ty = if self.next_trait_solver()
65+
&& matches!(relation.structurally_relate_aliases(), StructurallyRelateAliases::No)
66+
&& let ty::Alias(_, alias) = source_ty.kind()
67+
{
68+
let normalized_alias = relation.try_eagerly_normalize_alias(*alias);
69+
70+
if normalized_alias.is_ty_var() {
71+
normalized_alias
72+
} else {
73+
let Generalization { value_may_be_infer: generalized_ty } = self.generalize(
74+
relation.span(),
75+
GeneralizerState::ShallowStructurallyRelateAliases,
76+
target_vid,
77+
instantiation_variance,
78+
normalized_alias,
79+
&mut |alias| relation.try_eagerly_normalize_alias(alias),
80+
)?;
81+
82+
// The only way to get a tyvar back is if the outermost type is an alias.
83+
// However, here, though we know it *is* an alias, we initialize the generalizer
84+
// with `ShallowStructurallyRelateAliases` so we treat the outermost alias as rigid,
85+
// ensuring this is never a tyvar.
86+
assert!(!generalized_ty.is_ty_var());
87+
88+
generalized_ty
89+
}
90+
} else {
91+
// Generalize `source_ty` depending on the current variance. As an example, assume
92+
// `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference
93+
// variable.
94+
//
95+
// Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh
96+
// region/type inference variables.
97+
//
98+
// We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and
99+
// `?1 <: ?3`.
100+
let Generalization { value_may_be_infer: generalized_ty } = self.generalize(
101+
relation.span(),
102+
relation.structurally_relate_aliases().into(),
103+
target_vid,
104+
instantiation_variance,
105+
source_ty,
106+
&mut |alias| relation.try_eagerly_normalize_alias(alias),
107+
)?;
108+
109+
generalized_ty
110+
};
114111

115112
// Finally, relate `generalized_ty` to `source_ty`, as described in previous comment.
116113
//
@@ -239,7 +236,7 @@ impl<'tcx> InferCtxt<'tcx> {
239236
// constants and generic expressions are not yet handled correctly.
240237
let Generalization { value_may_be_infer: generalized_ct } = self.generalize(
241238
relation.span(),
242-
relation.structurally_relate_aliases(),
239+
relation.structurally_relate_aliases().into(),
243240
target_vid,
244241
ty::Invariant,
245242
source_ct,
@@ -279,7 +276,7 @@ impl<'tcx> InferCtxt<'tcx> {
279276
fn generalize<T: Into<Term<'tcx>> + Relate<TyCtxt<'tcx>>>(
280277
&self,
281278
span: Span,
282-
structurally_relate_aliases: StructurallyRelateAliases,
279+
initial_state: GeneralizerState,
283280
target_vid: impl Into<TermVid>,
284281
ambient_variance: ty::Variance,
285282
source_term: T,
@@ -303,10 +300,7 @@ impl<'tcx> InferCtxt<'tcx> {
303300
for_universe,
304301
root_term: source_term.into(),
305302
ambient_variance,
306-
state: match structurally_relate_aliases {
307-
StructurallyRelateAliases::No => GeneralizerState::Default,
308-
StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases,
309-
},
303+
state: initial_state,
310304
cache: Default::default(),
311305
normalize,
312306
};
@@ -365,6 +359,15 @@ enum GeneralizerState {
365359
StructurallyRelateAliases,
366360
}
367361

362+
impl From<StructurallyRelateAliases> for GeneralizerState {
363+
fn from(structurally_relate_aliases: StructurallyRelateAliases) -> Self {
364+
match structurally_relate_aliases {
365+
StructurallyRelateAliases::No => GeneralizerState::Default,
366+
StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases,
367+
}
368+
}
369+
}
370+
368371
/// The "generalizer" is used when handling inference variables.
369372
///
370373
/// The basic strategy for handling a constraint like `?A <: B` is to

0 commit comments

Comments
 (0)