Skip to content

Commit 685e48b

Browse files
committed
Auto merge of #66838 - eddyb:wf-skip-plus-global-caching, r=<try>
[WIP] [DO NOT MERGE] combine #66020 and #66821. That is, the two fixes for #65510, and only for perf testing purposes. The fact that they both work to a comparable extent, while touching different parts of the trait system, made me curious if there would be any gains from having both. r? @nikomatsakis
2 parents 2539b5f + ba8f8f8 commit 685e48b

File tree

4 files changed

+53
-110
lines changed

4 files changed

+53
-110
lines changed

src/librustc/traits/select.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,10 @@ struct TraitObligationStack<'prev, 'tcx> {
204204
#[derive(Clone, Default)]
205205
pub struct SelectionCache<'tcx> {
206206
hashmap: Lock<
207-
FxHashMap<ty::TraitRef<'tcx>, WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
207+
FxHashMap<
208+
ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>,
209+
WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>,
210+
>,
208211
>,
209212
}
210213

@@ -490,7 +493,9 @@ impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
490493

491494
#[derive(Clone, Default)]
492495
pub struct EvaluationCache<'tcx> {
493-
hashmap: Lock<FxHashMap<ty::PolyTraitRef<'tcx>, WithDepNode<EvaluationResult>>>,
496+
hashmap: Lock<
497+
FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>,
498+
>,
494499
}
495500

496501
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
@@ -1143,15 +1148,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11431148
let tcx = self.tcx();
11441149
if self.can_use_global_caches(param_env) {
11451150
let cache = tcx.evaluation_cache.hashmap.borrow();
1146-
if let Some(cached) = cache.get(&trait_ref) {
1151+
if let Some(cached) = cache.get(&param_env.and(trait_ref)) {
11471152
return Some(cached.get(tcx));
11481153
}
11491154
}
11501155
self.infcx
11511156
.evaluation_cache
11521157
.hashmap
11531158
.borrow()
1154-
.get(&trait_ref)
1159+
.get(&param_env.and(trait_ref))
11551160
.map(|v| v.get(tcx))
11561161
}
11571162

@@ -1182,7 +1187,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11821187
.evaluation_cache
11831188
.hashmap
11841189
.borrow_mut()
1185-
.insert(trait_ref, WithDepNode::new(dep_node, result));
1190+
.insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result));
11861191
return;
11871192
}
11881193
}
@@ -1195,7 +1200,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11951200
.evaluation_cache
11961201
.hashmap
11971202
.borrow_mut()
1198-
.insert(trait_ref, WithDepNode::new(dep_node, result));
1203+
.insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result));
11991204
}
12001205

12011206
/// For various reasons, it's possible for a subobligation
@@ -1575,7 +1580,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15751580
// rule seems to be pretty clearly safe and also still retains
15761581
// a very high hit rate (~95% when compiling rustc).
15771582
if !param_env.caller_bounds.is_empty() {
1578-
return false;
1583+
//return false;
15791584
}
15801585

15811586
// Avoid using the master cache during coherence and just rely
@@ -1602,15 +1607,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16021607
let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref;
16031608
if self.can_use_global_caches(param_env) {
16041609
let cache = tcx.selection_cache.hashmap.borrow();
1605-
if let Some(cached) = cache.get(&trait_ref) {
1610+
if let Some(cached) = cache.get(&param_env.and(*trait_ref)) {
16061611
return Some(cached.get(tcx));
16071612
}
16081613
}
16091614
self.infcx
16101615
.selection_cache
16111616
.hashmap
16121617
.borrow()
1613-
.get(trait_ref)
1618+
.get(&param_env.and(*trait_ref))
16141619
.map(|v| v.get(tcx))
16151620
}
16161621

@@ -1671,7 +1676,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16711676
tcx.selection_cache
16721677
.hashmap
16731678
.borrow_mut()
1674-
.insert(trait_ref, WithDepNode::new(dep_node, candidate));
1679+
.insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate));
16751680
return;
16761681
}
16771682
}
@@ -1685,7 +1690,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16851690
.selection_cache
16861691
.hashmap
16871692
.borrow_mut()
1688-
.insert(trait_ref, WithDepNode::new(dep_node, candidate));
1693+
.insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate));
16891694
}
16901695

16911696
fn assemble_candidates<'o>(

src/librustc/ty/wf.rs

+33-25
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub fn trait_obligations<'a, 'tcx>(
5353
item: Option<&'tcx hir::Item>,
5454
) -> Vec<traits::PredicateObligation<'tcx>> {
5555
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item };
56-
wf.compute_trait_ref(trait_ref, Elaborate::All);
56+
wf.compute_trait_ref(trait_ref, Elaborate::All, false);
5757
wf.normalize()
5858
}
5959

@@ -69,7 +69,7 @@ pub fn predicate_obligations<'a, 'tcx>(
6969
// (*) ok to skip binders, because wf code is prepared for it
7070
match *predicate {
7171
ty::Predicate::Trait(ref t) => {
72-
wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*)
72+
wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None, false); // (*)
7373
}
7474
ty::Predicate::RegionOutlives(..) => {
7575
}
@@ -163,14 +163,18 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
163163
}
164164

165165
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
166-
fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) {
166+
fn compute_trait_ref(
167+
&mut self,
168+
trait_ref: &ty::TraitRef<'tcx>,
169+
elaborate: Elaborate,
170+
is_proj: bool,
171+
) {
167172
let tcx = self.infcx.tcx;
168-
let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
169173

170174
let cause = self.cause(traits::MiscObligation);
171175
let param_env = self.param_env;
172176

173-
let item = &self.item;
177+
let item = self.item;
174178
let extend_cause_with_original_assoc_item_obligation = |
175179
cause: &mut traits::ObligationCause<'_>,
176180
pred: &ty::Predicate<'_>,
@@ -313,26 +317,30 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
313317
}
314318
};
315319

316-
if let Elaborate::All = elaborate {
317-
let trait_assoc_items = tcx.associated_items(trait_ref.def_id);
318-
319-
let predicates = obligations.iter()
320-
.map(|obligation| obligation.predicate.clone())
321-
.collect();
322-
let implied_obligations = traits::elaborate_predicates(tcx, predicates);
323-
let implied_obligations = implied_obligations.map(|pred| {
324-
let mut cause = cause.clone();
325-
extend_cause_with_original_assoc_item_obligation(
326-
&mut cause,
327-
&pred,
328-
trait_assoc_items.clone(),
329-
);
330-
traits::Obligation::new(cause, param_env, pred)
331-
});
332-
self.out.extend(implied_obligations);
333-
}
320+
if !is_proj {
321+
let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
322+
323+
if let Elaborate::All = elaborate {
324+
let trait_assoc_items = tcx.associated_items(trait_ref.def_id);
325+
326+
let predicates = obligations.iter()
327+
.map(|obligation| obligation.predicate.clone())
328+
.collect();
329+
let implied_obligations = traits::elaborate_predicates(tcx, predicates);
330+
let implied_obligations = implied_obligations.map(|pred| {
331+
let mut cause = cause.clone();
332+
extend_cause_with_original_assoc_item_obligation(
333+
&mut cause,
334+
&pred,
335+
trait_assoc_items.clone(),
336+
);
337+
traits::Obligation::new(cause, param_env, pred)
338+
});
339+
self.out.extend(implied_obligations);
340+
}
334341

335-
self.out.extend(obligations);
342+
self.out.extend(obligations);
343+
}
336344

337345
self.out.extend(trait_ref.substs.types()
338346
.filter(|ty| !ty.has_escaping_bound_vars())
@@ -350,7 +358,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
350358
// WF and (b) the trait-ref holds. (It may also be
351359
// normalizable and be WF that way.)
352360
let trait_ref = data.trait_ref(self.infcx.tcx);
353-
self.compute_trait_ref(&trait_ref, Elaborate::None);
361+
self.compute_trait_ref(&trait_ref, Elaborate::None, true);
354362

355363
if !data.has_escaping_bound_vars() {
356364
let predicate = trait_ref.to_predicate();

src/test/ui/associated-types/associated-types-overridden-binding.stderr

+2-9
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,6 @@ LL | trait Foo: Iterator<Item = i32> {}
66
LL | trait Bar: Foo<Item = u32> {}
77
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
88

9-
error[E0282]: type annotations needed
10-
--> $DIR/associated-types-overridden-binding.rs:7:1
11-
|
12-
LL | trait U32Iterator = I32Iterator<Item = u32>;
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
14-
15-
error: aborting due to 2 previous errors
9+
error: aborting due to previous error
1610

17-
Some errors have detailed explanations: E0282, E0284.
18-
For more information about an error, try `rustc --explain E0282`.
11+
For more information about this error, try `rustc --explain E0284`.
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,3 @@
1-
error[E0308]: mismatched types
2-
--> $DIR/issue-20831-debruijn.rs:28:5
3-
|
4-
LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
5-
LL | | // Not obvious, but there is an implicit lifetime here -------^
6-
LL | |
7-
LL | |
8-
... |
9-
LL | | self.sub = t;
10-
LL | | }
11-
| |_____^ lifetime mismatch
12-
|
13-
= note: expected type `'a`
14-
found type `'_`
15-
note: the anonymous lifetime #2 defined on the method body at 28:5...
16-
--> $DIR/issue-20831-debruijn.rs:28:5
17-
|
18-
LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
19-
LL | | // Not obvious, but there is an implicit lifetime here -------^
20-
LL | |
21-
LL | |
22-
... |
23-
LL | | self.sub = t;
24-
LL | | }
25-
| |_____^
26-
note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 26:6
27-
--> $DIR/issue-20831-debruijn.rs:26:6
28-
|
29-
LL | impl<'a> Publisher<'a> for MyStruct<'a> {
30-
| ^^
31-
32-
error[E0308]: mismatched types
33-
--> $DIR/issue-20831-debruijn.rs:28:5
34-
|
35-
LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
36-
LL | | // Not obvious, but there is an implicit lifetime here -------^
37-
LL | |
38-
LL | |
39-
... |
40-
LL | | self.sub = t;
41-
LL | | }
42-
| |_____^ lifetime mismatch
43-
|
44-
= note: expected type `'a`
45-
found type `'_`
46-
note: the lifetime `'a` as defined on the impl at 26:6...
47-
--> $DIR/issue-20831-debruijn.rs:26:6
48-
|
49-
LL | impl<'a> Publisher<'a> for MyStruct<'a> {
50-
| ^^
51-
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the method body at 28:5
52-
--> $DIR/issue-20831-debruijn.rs:28:5
53-
|
54-
LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
55-
LL | | // Not obvious, but there is an implicit lifetime here -------^
56-
LL | |
57-
LL | |
58-
... |
59-
LL | | self.sub = t;
60-
LL | | }
61-
| |_____^
62-
631
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
642
--> $DIR/issue-20831-debruijn.rs:28:5
653
|
@@ -92,7 +30,6 @@ LL | impl<'a> Publisher<'a> for MyStruct<'a> {
9230
expected Publisher<'_>
9331
found Publisher<'_>
9432

95-
error: aborting due to 3 previous errors
33+
error: aborting due to previous error
9634

97-
Some errors have detailed explanations: E0308, E0495.
98-
For more information about an error, try `rustc --explain E0308`.
35+
For more information about this error, try `rustc --explain E0495`.

0 commit comments

Comments
 (0)