Skip to content

Commit 0dac974

Browse files
committed
cache the world
1 parent 5a95672 commit 0dac974

File tree

6 files changed

+92
-23
lines changed

6 files changed

+92
-23
lines changed

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

+10-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,7 @@ 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 { fields: f, structurally_relate_aliases, ambient_variance, cache: Default::default() }
2830
}
2931
}
3032

@@ -74,9 +76,14 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
7476
return Ok(a);
7577
}
7678

79+
7780
let infcx = self.fields.infcx;
7881
let a = infcx.shallow_resolve(a);
7982
let b = infcx.shallow_resolve(b);
83+
84+
if self.cache.contains(&(self.ambient_variance, a, b)) {
85+
return Ok(a);
86+
}
8087

8188
match (a.kind(), b.kind()) {
8289
(&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
@@ -160,6 +167,8 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> {
160167
}
161168
}
162169

170+
assert!(self.cache.insert((self.ambient_variance, a, b)));
171+
163172
Ok(a)
164173
}
165174

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
@@ -2,6 +2,7 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
22
use rustc_type_ir::inherent::*;
33
use rustc_type_ir::visit::TypeVisitableExt;
44
use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
5+
use rustc_type_ir::data_structures::HashMap;
56

67
use crate::delegate::SolverDelegate;
78

@@ -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

+35-10
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;
@@ -587,7 +587,7 @@ where
587587
pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) {
588588
goal.predicate = goal
589589
.predicate
590-
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
590+
.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env));
591591
self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal);
592592
self.nested_goals.normalizes_to_goals.push(goal);
593593
}
@@ -596,7 +596,7 @@ where
596596
pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) {
597597
goal.predicate = goal
598598
.predicate
599-
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
599+
.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env));
600600
self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal);
601601
self.nested_goals.goals.push((source, goal));
602602
}
@@ -660,6 +660,7 @@ where
660660
term: I::Term,
661661
universe_of_term: ty::UniverseIndex,
662662
delegate: &'a D,
663+
cache: HashSet<I::Ty>,
663664
}
664665

665666
impl<D: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, D, I> {
@@ -677,6 +678,10 @@ where
677678
{
678679
type Result = ControlFlow<()>;
679680
fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
681+
if self.cache.contains(&t) {
682+
return ControlFlow::Continue(());
683+
}
684+
680685
match t.kind() {
681686
ty::Infer(ty::TyVar(vid)) => {
682687
if let ty::TermKind::Ty(term) = self.term.kind() {
@@ -689,17 +694,18 @@ where
689694
}
690695
}
691696

692-
self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())
697+
self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?;
693698
}
694-
ty::Placeholder(p) => self.check_nameable(p.universe()),
699+
ty::Placeholder(p) => self.check_nameable(p.universe())?,
695700
_ => {
696701
if t.has_non_region_infer() || t.has_placeholders() {
697-
t.super_visit_with(self)
698-
} else {
699-
ControlFlow::Continue(())
702+
t.super_visit_with(self)?
700703
}
701704
}
702705
}
706+
707+
assert!(self.cache.insert(t));
708+
ControlFlow::Continue(())
703709
}
704710

705711
fn visit_const(&mut self, c: I::Const) -> Self::Result {
@@ -734,6 +740,7 @@ where
734740
delegate: self.delegate,
735741
universe_of_term,
736742
term: goal.predicate.term,
743+
cache: Default::default(),
737744
};
738745
goal.predicate.alias.visit_with(&mut visitor).is_continue()
739746
&& goal.param_env.visit_with(&mut visitor).is_continue()
@@ -1021,6 +1028,17 @@ where
10211028
{
10221029
ecx: &'me mut EvalCtxt<'a, D>,
10231030
param_env: I::ParamEnv,
1031+
cache: HashMap<I::Ty, I::Ty>,
1032+
}
1033+
1034+
impl<'me, 'a, D, I> ReplaceAliasWithInfer<'me, 'a, D, I>
1035+
where
1036+
D: SolverDelegate<Interner = I>,
1037+
I: Interner,
1038+
{
1039+
fn new(ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv) -> Self {
1040+
ReplaceAliasWithInfer { ecx, param_env, cache: Default::default() }
1041+
}
10241042
}
10251043

10261044
impl<D, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, D, I>
@@ -1033,7 +1051,11 @@ where
10331051
}
10341052

10351053
fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
1036-
match ty.kind() {
1054+
if let Some(&entry) = self.cache.get(&ty) {
1055+
return entry;
1056+
}
1057+
1058+
let res = match ty.kind() {
10371059
ty::Alias(..) if !ty.has_escaping_bound_vars() => {
10381060
let infer_ty = self.ecx.next_ty_infer();
10391061
let normalizes_to = ty::PredicateKind::AliasRelate(
@@ -1048,7 +1070,10 @@ where
10481070
infer_ty
10491071
}
10501072
_ => ty.super_fold_with(self),
1051-
}
1073+
};
1074+
1075+
assert!(self.cache.insert(ty, res).is_none());
1076+
res
10521077
}
10531078

10541079
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

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
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
6+
// check-pass
47

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

@@ -15,7 +18,12 @@ trait Trait {
1518
type Assoc: ?Sized;
1619
}
1720
impl<T: ?Sized + Trait> Trait for W<T, T> {
21+
#[cfg(any(ai_current, ai_next))]
1822
type Assoc = W<T::Assoc, Id<T::Assoc>>;
23+
#[cfg(any(ia_current, ia_next))]
24+
type Assoc = W<Id<T::Assoc>, T::Assoc>;
25+
#[cfg(any(ii_current, ii_next))]
26+
type Assoc = W<Id<T::Assoc>, Id<T::Assoc>>;
1927
}
2028

2129
trait Overlap<T: ?Sized> {}

0 commit comments

Comments
 (0)