Skip to content

Commit 92bb985

Browse files
committed
Auto merge of #151746 - jdonszelmann:eagerly-normalize-in-generalize, r=<try>
Eagerly normalize in generalize
2 parents 370143f + 5bd20bb commit 92bb985

19 files changed

Lines changed: 324 additions & 104 deletions

File tree

compiler/rustc_borrowck/src/type_check/relate_tys.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -377,19 +377,20 @@ impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
377377
);
378378
}
379379

380+
(_, ty::Alias(..)) | (ty::Alias(..), _) if infcx.next_trait_solver() => {
381+
self.register_alias_relate_predicate(a, b);
382+
}
383+
380384
(&ty::Infer(ty::TyVar(a_vid)), _) => {
381385
infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)?
382386
}
383387

384388
(
385389
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
386390
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
387-
) if a_def_id == b_def_id || infcx.next_trait_solver() => {
391+
) if a_def_id == b_def_id => {
392+
debug_assert!(!infcx.next_trait_solver());
388393
super_combine_tys(&infcx.infcx, self, a, b).map(|_| ()).or_else(|err| {
389-
// This behavior is only there for the old solver, the new solver
390-
// shouldn't ever fail. Instead, it unconditionally emits an
391-
// alias-relate goal.
392-
assert!(!self.type_checker.infcx.next_trait_solver());
393394
self.cx().dcx().span_delayed_bug(
394395
self.span(),
395396
"failure to relate an opaque to itself should result in an error later on",
@@ -399,7 +400,7 @@ impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
399400
}
400401
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
401402
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
402-
if def_id.is_local() && !self.type_checker.infcx.next_trait_solver() =>
403+
if def_id.is_local() =>
403404
{
404405
self.relate_opaques(a, b)?;
405406
}
@@ -616,4 +617,9 @@ impl<'b, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_
616617
}
617618
})]);
618619
}
620+
621+
fn try_eagerly_normalize_alias(&mut self, _alias: ty::AliasTy<'tcx>) -> Ty<'tcx> {
622+
// Past hir typeck, so we don't have to worry about type inference anymore.
623+
self.type_checker.infcx.next_ty_var(self.span())
624+
}
619625
}

compiler/rustc_infer/src/infer/at.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ impl<'a, 'tcx> At<'a, 'tcx> {
140140
ty::Contravariant,
141141
actual,
142142
self.cause.span,
143+
&mut |alias| {
144+
self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias)
145+
},
143146
)
144147
.map(|goals| self.goals_to_obligations(goals))
145148
} else {
@@ -173,6 +176,9 @@ impl<'a, 'tcx> At<'a, 'tcx> {
173176
ty::Covariant,
174177
actual,
175178
self.cause.span,
179+
&mut |alias| {
180+
self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias)
181+
},
176182
)
177183
.map(|goals| self.goals_to_obligations(goals))
178184
} else {
@@ -225,6 +231,9 @@ impl<'a, 'tcx> At<'a, 'tcx> {
225231
ty::Invariant,
226232
actual,
227233
self.cause.span,
234+
&mut |alias| {
235+
self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias)
236+
},
228237
)
229238
.map(|goals| self.goals_to_obligations(goals))
230239
} else {

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::cell::{Cell, RefCell};
2-
use std::fmt;
2+
use std::{fmt, mem};
33

44
pub use at::DefineOpaqueTypes;
55
use free_regions::RegionRelations;
@@ -21,6 +21,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
2121
use rustc_macros::extension;
2222
pub use rustc_macros::{TypeFoldable, TypeVisitable};
2323
use rustc_middle::bug;
24+
use rustc_middle::hooks::TypeErasedInfcx;
2425
use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
2526
use rustc_middle::mir::ConstraintCategory;
2627
use rustc_middle::traits::select;
@@ -1465,6 +1466,17 @@ impl<'tcx> InferCtxt<'tcx> {
14651466
}
14661467
}
14671468

1469+
pub fn try_eagerly_normalize_alias<'a>(
1470+
&'a self,
1471+
param_env: ty::ParamEnv<'tcx>,
1472+
span: Span,
1473+
alias: ty::AliasTy<'tcx>,
1474+
) -> Ty<'tcx> {
1475+
let erased =
1476+
unsafe { mem::transmute::<&'a InferCtxt<'tcx>, TypeErasedInfcx<'a, 'tcx>>(self) };
1477+
self.tcx.try_eagerly_normalize_alias(erased, param_env, span, alias)
1478+
}
1479+
14681480
/// Attach a callback to be invoked on each root obligation evaluated in the new trait solver.
14691481
pub fn attach_obligation_inspector(&self, inspector: ObligationInspector<'tcx>) {
14701482
debug_assert!(

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

Lines changed: 90 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ impl<'tcx> InferCtxt<'tcx> {
7676
target_vid,
7777
instantiation_variance,
7878
source_ty,
79+
&mut |alias| relation.try_eagerly_normalize_alias(alias),
7980
)?;
8081

8182
// Constrain `b_vid` to the generalized type `generalized_ty`.
@@ -210,6 +211,7 @@ impl<'tcx> InferCtxt<'tcx> {
210211
target_vid,
211212
ty::Invariant,
212213
source_ct,
214+
&mut |alias| relation.try_eagerly_normalize_alias(alias),
213215
)?;
214216

215217
debug_assert!(!generalized_ct.is_ct_infer());
@@ -249,6 +251,7 @@ impl<'tcx> InferCtxt<'tcx> {
249251
target_vid: impl Into<TermVid>,
250252
ambient_variance: ty::Variance,
251253
source_term: T,
254+
normalize: &mut dyn FnMut(ty::AliasTy<'tcx>) -> Ty<'tcx>,
252255
) -> RelateResult<'tcx, Generalization<T>> {
253256
assert!(!source_term.has_escaping_bound_vars());
254257
let (for_universe, root_vid) = match target_vid.into() {
@@ -264,15 +267,20 @@ impl<'tcx> InferCtxt<'tcx> {
264267
let mut generalizer = Generalizer {
265268
infcx: self,
266269
span,
267-
structurally_relate_aliases,
268270
root_vid,
269271
for_universe,
270272
root_term: source_term.into(),
271273
ambient_variance,
272-
in_alias: false,
274+
state: match structurally_relate_aliases {
275+
StructurallyRelateAliases::No => GeneralizerState::Default,
276+
StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases,
277+
},
273278
cache: Default::default(),
279+
normalize,
274280
};
275281

282+
debug!(?root_vid, ?generalizer.root_term, "generalize");
283+
276284
let value_may_be_infer = generalizer.relate(source_term, source_term)?;
277285
Ok(Generalization { value_may_be_infer })
278286
}
@@ -317,6 +325,16 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxUniverse {
317325
}
318326
}
319327

328+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
329+
enum GeneralizerState {
330+
/// Treat aliases as potentially normalizable.
331+
Default,
332+
IncompletelyRelateHigherRankedAlias,
333+
/// Only one layer
334+
ShallowStructurallyRelateAliases,
335+
StructurallyRelateAliases,
336+
}
337+
320338
/// The "generalizer" is used when handling inference variables.
321339
///
322340
/// The basic strategy for handling a constraint like `?A <: B` is to
@@ -335,10 +353,6 @@ struct Generalizer<'me, 'tcx> {
335353

336354
span: Span,
337355

338-
/// Whether aliases should be related structurally. If not, we have to
339-
/// be careful when generalizing aliases.
340-
structurally_relate_aliases: StructurallyRelateAliases,
341-
342356
/// The vid of the type variable that is in the process of being
343357
/// instantiated. If we find this within the value we are folding,
344358
/// that means we would have created a cyclic value.
@@ -361,9 +375,13 @@ struct Generalizer<'me, 'tcx> {
361375
/// This is necessary to correctly handle
362376
/// `<T as Bar<<?0 as Foo>::Assoc>::Assoc == ?0`. This equality can
363377
/// hold by either normalizing the outer or the inner associated type.
364-
in_alias: bool,
378+
state: GeneralizerState,
365379

366-
cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>,
380+
cache: SsoHashMap<(Ty<'tcx>, ty::Variance, GeneralizerState), Ty<'tcx>>,
381+
382+
/// Normalize an alias in the trait solver.
383+
/// If normalization fails, a fresh infer var is returned.
384+
normalize: &'me mut dyn FnMut(ty::AliasTy<'tcx>) -> Ty<'tcx>,
367385
}
368386

369387
impl<'tcx> Generalizer<'_, 'tcx> {
@@ -399,27 +417,51 @@ impl<'tcx> Generalizer<'_, 'tcx> {
399417
/// continue generalizing the alias. This ends up pulling down the universe of the
400418
/// inference variable and is incomplete in case the alias would normalize to a type
401419
/// which does not mention that inference variable.
402-
fn generalize_alias_ty(
420+
fn handle_alias_ty(
403421
&mut self,
422+
alias_ty: Ty<'tcx>,
404423
alias: ty::AliasTy<'tcx>,
405424
) -> 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
412-
if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias {
413-
return Ok(self.next_ty_var_for_alias());
425+
match self.state {
426+
GeneralizerState::ShallowStructurallyRelateAliases => {
427+
// We can switch back to default, we've treated one layer as rigid by doing this operation.
428+
self.state = GeneralizerState::Default;
429+
let res = relate::structurally_relate_tys(self, alias_ty, alias_ty);
430+
self.state = GeneralizerState::ShallowStructurallyRelateAliases;
431+
return res;
432+
}
433+
GeneralizerState::StructurallyRelateAliases => {
434+
return relate::structurally_relate_tys(self, alias_ty, alias_ty);
435+
}
436+
GeneralizerState::Default
437+
if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() =>
438+
{
439+
// We do not eagerly replace aliases with inference variables if they have
440+
// escaping bound vars, see the method comment for details. However, when we
441+
// are inside of an alias with escaping bound vars replacing nested aliases
442+
// with inference variables can cause incorrect ambiguity.
443+
//
444+
// cc trait-system-refactor-initiative#110
445+
let normalized_alias = (self.normalize)(alias);
446+
447+
self.state = GeneralizerState::ShallowStructurallyRelateAliases;
448+
// recursively generalize, trCeat the outer alias as rigid to avoid infinite recursion
449+
let res = self.relate(normalized_alias, normalized_alias);
450+
451+
// only one way to get here
452+
self.state = GeneralizerState::Default;
453+
454+
return res;
455+
}
456+
GeneralizerState::Default | GeneralizerState::IncompletelyRelateHigherRankedAlias => {}
414457
}
415458

416-
let is_nested_alias = mem::replace(&mut self.in_alias, true);
459+
let previous_state =
460+
mem::replace(&mut self.state, GeneralizerState::IncompletelyRelateHigherRankedAlias);
417461
let result = match self.relate(alias, alias) {
418462
Ok(alias) => Ok(alias.to_ty(self.cx())),
419-
Err(e) => {
420-
if is_nested_alias {
421-
return Err(e);
422-
} else {
463+
Err(e) => match previous_state {
464+
GeneralizerState::Default => {
423465
let mut visitor = MaxUniverse::new();
424466
alias.visit_with(&mut visitor);
425467
let infer_replacement_is_complete =
@@ -432,9 +474,14 @@ impl<'tcx> Generalizer<'_, 'tcx> {
432474
debug!("generalization failure in alias");
433475
Ok(self.next_ty_var_for_alias())
434476
}
435-
}
477+
GeneralizerState::IncompletelyRelateHigherRankedAlias => return Err(e),
478+
479+
// Early return.
480+
GeneralizerState::ShallowStructurallyRelateAliases
481+
| GeneralizerState::StructurallyRelateAliases => unreachable!(),
482+
},
436483
};
437-
self.in_alias = is_nested_alias;
484+
self.state = previous_state;
438485
result
439486
}
440487
}
@@ -488,7 +535,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
488535
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
489536
assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
490537

491-
if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) {
538+
if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.state)) {
492539
return Ok(result);
493540
}
494541

@@ -553,9 +600,15 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
553600
// cc trait-system-refactor-initiative#108
554601
if self.infcx.next_trait_solver()
555602
&& !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
556-
&& self.in_alias
557603
{
558-
inner.type_variables().equate(vid, new_var_id);
604+
match self.state {
605+
GeneralizerState::IncompletelyRelateHigherRankedAlias => {
606+
inner.type_variables().equate(vid, new_var_id);
607+
}
608+
GeneralizerState::Default
609+
| GeneralizerState::ShallowStructurallyRelateAliases
610+
| GeneralizerState::StructurallyRelateAliases => {}
611+
}
559612
}
560613

561614
debug!("replacing original vid={:?} with new={:?}", vid, new_var_id);
@@ -584,15 +637,12 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
584637
}
585638
}
586639

587-
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-
},
640+
ty::Alias(_, data) => self.handle_alias_ty(t, data),
591641

592642
_ => relate::structurally_relate_tys(self, t, t),
593643
}?;
594644

595-
self.cache.insert((t, self.ambient_variance, self.in_alias), g);
645+
self.cache.insert((t, self.ambient_variance, self.state), g);
596646
Ok(g)
597647
}
598648

@@ -683,9 +733,15 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
683733
// for more details.
684734
if self.infcx.next_trait_solver()
685735
&& !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
686-
&& self.in_alias
687736
{
688-
variable_table.union(vid, new_var_id);
737+
match self.state {
738+
GeneralizerState::IncompletelyRelateHigherRankedAlias => {
739+
variable_table.union(vid, new_var_id);
740+
}
741+
GeneralizerState::Default
742+
| GeneralizerState::ShallowStructurallyRelateAliases
743+
| GeneralizerState::StructurallyRelateAliases => {}
744+
}
689745
}
690746
Ok(ty::Const::new_var(self.cx(), new_var_id))
691747
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,4 +299,8 @@ impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
299299
ty::AliasRelationDirection::Equate,
300300
))]);
301301
}
302+
303+
fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy<'tcx>) -> Ty<'tcx> {
304+
self.infcx.try_eagerly_normalize_alias(self.param_env(), self.span(), alias)
305+
}
302306
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,4 +396,13 @@ impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for TypeRelating<'_, 'tcx>
396396
}
397397
})]);
398398
}
399+
400+
fn try_eagerly_normalize_alias(
401+
&mut self,
402+
_alias: rustc_type_ir::AliasTy<<InferCtxt<'tcx> as rustc_type_ir::InferCtxtLike>::Interner>,
403+
) -> <<InferCtxt<'tcx> as rustc_type_ir::InferCtxtLike>::Interner as rustc_type_ir::Interner>::Ty
404+
{
405+
// We only try to eagerly normalize aliases if we're using the new solver.
406+
unreachable!()
407+
}
399408
}

compiler/rustc_interface/src/passes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -901,7 +901,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
901901
rustc_hir_typeck::provide(&mut providers.queries);
902902
ty::provide(&mut providers.queries);
903903
traits::provide(&mut providers.queries);
904-
solve::provide(&mut providers.queries);
904+
solve::provide(providers);
905905
rustc_passes::provide(&mut providers.queries);
906906
rustc_traits::provide(&mut providers.queries);
907907
rustc_ty_utils::provide(&mut providers.queries);

0 commit comments

Comments
 (0)