Skip to content

Commit a9ea892

Browse files
committed
cache the world
1 parent 5a95672 commit a9ea892

File tree

6 files changed

+97
-27
lines changed

6 files changed

+97
-27
lines changed

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

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_data_structures::fx::FxHashSet;
12
use rustc_middle::traits::solve::Goal;
23
use rustc_middle::ty::relate::{
34
Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances,
@@ -16,6 +17,7 @@ pub struct TypeRelating<'combine, 'a, 'tcx> {
1617
fields: &'combine mut CombineFields<'a, 'tcx>,
1718
structurally_relate_aliases: StructurallyRelateAliases,
1819
ambient_variance: ty::Variance,
20+
cache: FxHashSet<(ty::Variance, Ty<'tcx>, Ty<'tcx>)>,
1921
}
2022

2123
impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> {
@@ -24,7 +26,12 @@ impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> {
2426
structurally_relate_aliases: StructurallyRelateAliases,
2527
ambient_variance: ty::Variance,
2628
) -> TypeRelating<'combine, 'infcx, 'tcx> {
27-
TypeRelating { fields: f, structurally_relate_aliases, ambient_variance }
29+
TypeRelating {
30+
fields: f,
31+
structurally_relate_aliases,
32+
ambient_variance,
33+
cache: Default::default(),
34+
}
2835
}
2936
}
3037

@@ -78,6 +85,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
7885
let a = infcx.shallow_resolve(a);
7986
let b = infcx.shallow_resolve(b);
8087

88+
if self.cache.contains(&(self.ambient_variance, a, b)) {
89+
return Ok(a);
90+
}
91+
8192
match (a.kind(), b.kind()) {
8293
(&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
8394
match self.ambient_variance {
@@ -160,6 +171,8 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
160171
}
161172
}
162173

174+
assert!(self.cache.insert((self.ambient_variance, a, b)));
175+
163176
Ok(a)
164177
}
165178

compiler/rustc_infer/src/infer/resolve.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_data_structures::fx::FxHashMap;
12
use rustc_middle::bug;
23
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
34
use rustc_middle::ty::visit::TypeVisitableExt;
@@ -15,12 +16,13 @@ use super::{FixupError, FixupResult, InferCtxt};
1516
/// points for correctness.
1617
pub struct OpportunisticVarResolver<'a, 'tcx> {
1718
infcx: &'a InferCtxt<'tcx>,
19+
cache: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
1820
}
1921

2022
impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
2123
#[inline]
2224
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
23-
OpportunisticVarResolver { infcx }
25+
OpportunisticVarResolver { infcx, cache: Default::default() }
2426
}
2527
}
2628

@@ -31,12 +33,19 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> {
3133

3234
#[inline]
3335
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
34-
if !t.has_non_region_infer() {
36+
if let Some(&ty) = self.cache.get(&t) {
37+
return ty;
38+
}
39+
40+
let res = if !t.has_non_region_infer() {
3541
t // micro-optimize -- if there is nothing in this type that this fold affects...
3642
} else {
3743
let t = self.infcx.shallow_resolve(t);
3844
t.super_fold_with(self)
39-
}
45+
};
46+
47+
assert!(self.cache.insert(t, res).is_none());
48+
res
4049
}
4150

4251
fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {

compiler/rustc_middle/src/ty/fold.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_data_structures::fx::FxIndexMap;
1+
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
22
use rustc_hir::def_id::DefId;
33
pub use rustc_type_ir::fold::{
44
FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region, shift_vars,
@@ -164,11 +164,13 @@ struct BoundVarReplacer<'tcx, D> {
164164
current_index: ty::DebruijnIndex,
165165

166166
delegate: D,
167+
168+
cache: FxHashMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>,
167169
}
168170

169171
impl<'tcx, D: BoundVarReplacerDelegate<'tcx>> BoundVarReplacer<'tcx, D> {
170172
fn new(tcx: TyCtxt<'tcx>, delegate: D) -> Self {
171-
BoundVarReplacer { tcx, current_index: ty::INNERMOST, delegate }
173+
BoundVarReplacer { tcx, current_index: ty::INNERMOST, delegate, cache: Default::default() }
172174
}
173175
}
174176

@@ -191,15 +193,22 @@ where
191193
}
192194

193195
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
194-
match *t.kind() {
196+
if let Some(&ty) = self.cache.get(&(self.current_index, t)) {
197+
return ty;
198+
}
199+
200+
let res = match *t.kind() {
195201
ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
196202
let ty = self.delegate.replace_ty(bound_ty);
197203
debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST));
198204
ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32())
199205
}
200206
_ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
201207
_ => t,
202-
}
208+
};
209+
210+
assert!(self.cache.insert((self.current_index, t), res).is_none());
211+
res
203212
}
204213

205214
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {

compiler/rustc_next_trait_solver/src/resolve.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_type_ir::data_structures::HashMap;
12
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
23
use rustc_type_ir::inherent::*;
34
use rustc_type_ir::visit::TypeVisitableExt;
@@ -15,11 +16,12 @@ where
1516
I: Interner,
1617
{
1718
delegate: &'a D,
19+
cache: HashMap<I::Ty, I::Ty>,
1820
}
1921

2022
impl<'a, D: SolverDelegate> EagerResolver<'a, D> {
2123
pub fn new(delegate: &'a D) -> Self {
22-
EagerResolver { delegate }
24+
EagerResolver { delegate, cache: Default::default() }
2325
}
2426
}
2527

@@ -29,7 +31,11 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerResolv
2931
}
3032

3133
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
32-
match t.kind() {
34+
if let Some(&ty) = self.cache.get(&t) {
35+
return ty;
36+
}
37+
38+
let res = match t.kind() {
3339
ty::Infer(ty::TyVar(vid)) => {
3440
let resolved = self.delegate.opportunistic_resolve_ty_var(vid);
3541
if t != resolved && resolved.has_infer() {
@@ -47,7 +53,10 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerResolv
4753
t
4854
}
4955
}
50-
}
56+
};
57+
58+
assert!(self.cache.insert(t, res).is_none());
59+
res
5160
}
5261

5362
fn fold_region(&mut self, r: I::Region) -> I::Region {

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

+37-14
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::ops::ControlFlow;
33
use derive_where::derive_where;
44
#[cfg(feature = "nightly")]
55
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
6-
use rustc_type_ir::data_structures::ensure_sufficient_stack;
6+
use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack};
77
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
88
use rustc_type_ir::inherent::*;
99
use rustc_type_ir::relate::Relate;
@@ -585,18 +585,16 @@ where
585585

586586
#[instrument(level = "trace", skip(self))]
587587
pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) {
588-
goal.predicate = goal
589-
.predicate
590-
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
588+
goal.predicate =
589+
goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env));
591590
self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal);
592591
self.nested_goals.normalizes_to_goals.push(goal);
593592
}
594593

595594
#[instrument(level = "debug", skip(self))]
596595
pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) {
597-
goal.predicate = goal
598-
.predicate
599-
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
596+
goal.predicate =
597+
goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env));
600598
self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal);
601599
self.nested_goals.goals.push((source, goal));
602600
}
@@ -660,6 +658,7 @@ where
660658
term: I::Term,
661659
universe_of_term: ty::UniverseIndex,
662660
delegate: &'a D,
661+
cache: HashSet<I::Ty>,
663662
}
664663

665664
impl<D: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, D, I> {
@@ -677,6 +676,10 @@ where
677676
{
678677
type Result = ControlFlow<()>;
679678
fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
679+
if self.cache.contains(&t) {
680+
return ControlFlow::Continue(());
681+
}
682+
680683
match t.kind() {
681684
ty::Infer(ty::TyVar(vid)) => {
682685
if let ty::TermKind::Ty(term) = self.term.kind() {
@@ -689,17 +692,18 @@ where
689692
}
690693
}
691694

692-
self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())
695+
self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?;
693696
}
694-
ty::Placeholder(p) => self.check_nameable(p.universe()),
697+
ty::Placeholder(p) => self.check_nameable(p.universe())?,
695698
_ => {
696699
if t.has_non_region_infer() || t.has_placeholders() {
697-
t.super_visit_with(self)
698-
} else {
699-
ControlFlow::Continue(())
700+
t.super_visit_with(self)?
700701
}
701702
}
702703
}
704+
705+
assert!(self.cache.insert(t));
706+
ControlFlow::Continue(())
703707
}
704708

705709
fn visit_const(&mut self, c: I::Const) -> Self::Result {
@@ -734,6 +738,7 @@ where
734738
delegate: self.delegate,
735739
universe_of_term,
736740
term: goal.predicate.term,
741+
cache: Default::default(),
737742
};
738743
goal.predicate.alias.visit_with(&mut visitor).is_continue()
739744
&& goal.param_env.visit_with(&mut visitor).is_continue()
@@ -1021,6 +1026,17 @@ where
10211026
{
10221027
ecx: &'me mut EvalCtxt<'a, D>,
10231028
param_env: I::ParamEnv,
1029+
cache: HashMap<I::Ty, I::Ty>,
1030+
}
1031+
1032+
impl<'me, 'a, D, I> ReplaceAliasWithInfer<'me, 'a, D, I>
1033+
where
1034+
D: SolverDelegate<Interner = I>,
1035+
I: Interner,
1036+
{
1037+
fn new(ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv) -> Self {
1038+
ReplaceAliasWithInfer { ecx, param_env, cache: Default::default() }
1039+
}
10241040
}
10251041

10261042
impl<D, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, D, I>
@@ -1033,7 +1049,11 @@ where
10331049
}
10341050

10351051
fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
1036-
match ty.kind() {
1052+
if let Some(&entry) = self.cache.get(&ty) {
1053+
return entry;
1054+
}
1055+
1056+
let res = match ty.kind() {
10371057
ty::Alias(..) if !ty.has_escaping_bound_vars() => {
10381058
let infer_ty = self.ecx.next_ty_infer();
10391059
let normalizes_to = ty::PredicateKind::AliasRelate(
@@ -1048,7 +1068,10 @@ where
10481068
infer_ty
10491069
}
10501070
_ => ty.super_fold_with(self),
1051-
}
1071+
};
1072+
1073+
assert!(self.cache.insert(ty, res).is_none());
1074+
res
10521075
}
10531076

10541077
fn fold_const(&mut self, ct: I::Const) -> I::Const {

tests/ui/traits/coherence-alias-hang.rs renamed to tests/ui/traits/next-solver/overflow/coherence-alias-hang.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//@ check-pass
2-
//@ revisions: current next
3-
//[next]@ compile-flags: -Znext-solver
2+
//@ revisions: ai_current ai_next ia_current ia_next ii_current ii_next
3+
//@[ai_next] compile-flags: -Znext-solver
4+
//@[ia_next] compile-flags: -Znext-solver
5+
//@[ii_next] compile-flags: -Znext-solver
46

57
// Regression test for nalgebra hang <https://github.com/rust-lang/rust/issues/130056>.
68

@@ -15,7 +17,12 @@ trait Trait {
1517
type Assoc: ?Sized;
1618
}
1719
impl<T: ?Sized + Trait> Trait for W<T, T> {
20+
#[cfg(any(ai_current, ai_next))]
1821
type Assoc = W<T::Assoc, Id<T::Assoc>>;
22+
#[cfg(any(ia_current, ia_next))]
23+
type Assoc = W<Id<T::Assoc>, T::Assoc>;
24+
#[cfg(any(ii_current, ii_next))]
25+
type Assoc = W<Id<T::Assoc>, Id<T::Assoc>>;
1926
}
2027

2128
trait Overlap<T: ?Sized> {}

0 commit comments

Comments
 (0)