Skip to content

Commit fe57f83

Browse files
committed
Auto merge of #68966 - jonas-schievink:coherence-perf, r=<try>
Improve performance of coherence checks The biggest perf improvement in here is expected to come from the removal of the remaining #43355 warning code since the effectively runs the expensive parts of coherence *twice* (which can even be visualized by obtaining a flamegraph https://twitter.com/sheevink/status/1225963187511709696).
2 parents 85ffd44 + 14a15d6 commit fe57f83

File tree

10 files changed

+76
-132
lines changed

10 files changed

+76
-132
lines changed

src/librustc/query/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,8 @@ rustc_queries! {
647647
query trait_impls_of(key: DefId) -> &'tcx ty::trait_def::TraitImpls {
648648
desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) }
649649
}
650-
query specialization_graph_of(_: DefId) -> &'tcx specialization_graph::Graph {
650+
query specialization_graph_of(key: DefId) -> &'tcx specialization_graph::Graph {
651+
desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(key) }
651652
cache_on_disk_if { true }
652653
}
653654
query is_object_safe(key: DefId) -> bool {

src/librustc/traits/coherence.rs

+6-17
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
77
use crate::infer::{CombinedSnapshot, InferOk};
88
use crate::traits::select::IntercrateAmbiguityCause;
9-
use crate::traits::IntercrateMode;
109
use crate::traits::SkipLeakCheck;
1110
use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext};
1211
use crate::ty::fold::TypeFoldable;
@@ -27,7 +26,7 @@ enum InCrate {
2726
#[derive(Debug, Copy, Clone)]
2827
pub enum Conflict {
2928
Upstream,
30-
Downstream { used_to_be_broken: bool },
29+
Downstream,
3130
}
3231

3332
pub struct OverlapResult<'tcx> {
@@ -53,7 +52,6 @@ pub fn overlapping_impls<F1, F2, R>(
5352
tcx: TyCtxt<'_>,
5453
impl1_def_id: DefId,
5554
impl2_def_id: DefId,
56-
intercrate_mode: IntercrateMode,
5755
skip_leak_check: SkipLeakCheck,
5856
on_overlap: F1,
5957
no_overlap: F2,
@@ -65,13 +63,12 @@ where
6563
debug!(
6664
"overlapping_impls(\
6765
impl1_def_id={:?}, \
68-
impl2_def_id={:?},
69-
intercrate_mode={:?})",
70-
impl1_def_id, impl2_def_id, intercrate_mode
66+
impl2_def_id={:?})",
67+
impl1_def_id, impl2_def_id,
7168
);
7269

7370
let overlaps = tcx.infer_ctxt().enter(|infcx| {
74-
let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
71+
let selcx = &mut SelectionContext::intercrate(&infcx);
7572
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).is_some()
7673
});
7774

@@ -83,7 +80,7 @@ where
8380
// this time tracking intercrate ambuiguity causes for better
8481
// diagnostics. (These take time and can lead to false errors.)
8582
tcx.infer_ctxt().enter(|infcx| {
86-
let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
83+
let selcx = &mut SelectionContext::intercrate(&infcx);
8784
selcx.enable_tracking_intercrate_ambiguity_causes();
8885
on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).unwrap())
8986
})
@@ -202,15 +199,7 @@ pub fn trait_ref_is_knowable<'tcx>(
202199
if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() {
203200
// A downstream or cousin crate is allowed to implement some
204201
// substitution of this trait-ref.
205-
206-
// A trait can be implementable for a trait ref by both the current
207-
// crate and crates downstream of it. Older versions of rustc
208-
// were not aware of this, causing incoherence (issue #43355).
209-
let used_to_be_broken = orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok();
210-
if used_to_be_broken {
211-
debug!("trait_ref_is_knowable({:?}) - USED TO BE BROKEN", trait_ref);
212-
}
213-
return Some(Conflict::Downstream { used_to_be_broken });
202+
return Some(Conflict::Downstream);
214203
}
215204

216205
if trait_ref_is_local_or_fundamental(tcx, trait_ref) {

src/librustc/traits/mod.rs

-7
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,6 @@ pub use self::chalk_fulfill::{
7676

7777
pub use self::types::*;
7878

79-
/// Whether to enable bug compatibility with issue #43355.
80-
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
81-
pub enum IntercrateMode {
82-
Issue43355,
83-
Fixed,
84-
}
85-
8679
/// Whether to skip the leak check, as part of a future compatibility warning step.
8780
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
8881
pub enum SkipLeakCheck {

src/librustc/traits/select.rs

+15-29
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ use super::DerivedObligationCause;
1717
use super::Selection;
1818
use super::SelectionResult;
1919
use super::TraitNotObjectSafe;
20+
use super::TraitQueryMode;
2021
use super::{BuiltinDerivedObligation, ImplDerivedObligation, ObligationCauseCode};
21-
use super::{IntercrateMode, TraitQueryMode};
2222
use super::{ObjectCastObligation, Obligation};
2323
use super::{ObligationCause, PredicateObligation, TraitObligation};
2424
use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented};
@@ -78,7 +78,7 @@ pub struct SelectionContext<'cx, 'tcx> {
7878
/// other words, we consider `$0: Bar` to be unimplemented if
7979
/// there is no type that the user could *actually name* that
8080
/// would satisfy it. This avoids crippling inference, basically.
81-
intercrate: Option<IntercrateMode>,
81+
intercrate: bool,
8282

8383
intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
8484

@@ -216,22 +216,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
216216
SelectionContext {
217217
infcx,
218218
freshener: infcx.freshener(),
219-
intercrate: None,
219+
intercrate: false,
220220
intercrate_ambiguity_causes: None,
221221
allow_negative_impls: false,
222222
query_mode: TraitQueryMode::Standard,
223223
}
224224
}
225225

226-
pub fn intercrate(
227-
infcx: &'cx InferCtxt<'cx, 'tcx>,
228-
mode: IntercrateMode,
229-
) -> SelectionContext<'cx, 'tcx> {
230-
debug!("intercrate({:?})", mode);
226+
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
231227
SelectionContext {
232228
infcx,
233229
freshener: infcx.freshener(),
234-
intercrate: Some(mode),
230+
intercrate: true,
235231
intercrate_ambiguity_causes: None,
236232
allow_negative_impls: false,
237233
query_mode: TraitQueryMode::Standard,
@@ -246,7 +242,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
246242
SelectionContext {
247243
infcx,
248244
freshener: infcx.freshener(),
249-
intercrate: None,
245+
intercrate: false,
250246
intercrate_ambiguity_causes: None,
251247
allow_negative_impls,
252248
query_mode: TraitQueryMode::Standard,
@@ -261,7 +257,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
261257
SelectionContext {
262258
infcx,
263259
freshener: infcx.freshener(),
264-
intercrate: None,
260+
intercrate: false,
265261
intercrate_ambiguity_causes: None,
266262
allow_negative_impls: false,
267263
query_mode,
@@ -274,7 +270,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
274270
/// false overflow results (#47139) and because it costs
275271
/// computation time.
276272
pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
277-
assert!(self.intercrate.is_some());
273+
assert!(self.intercrate);
278274
assert!(self.intercrate_ambiguity_causes.is_none());
279275
self.intercrate_ambiguity_causes = Some(vec![]);
280276
debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
@@ -284,7 +280,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
284280
/// was enabled and disables tracking at the same time. If
285281
/// tracking is not enabled, just returns an empty vector.
286282
pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> {
287-
assert!(self.intercrate.is_some());
283+
assert!(self.intercrate);
288284
self.intercrate_ambiguity_causes.take().unwrap_or(vec![])
289285
}
290286

@@ -560,7 +556,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
560556
) -> Result<EvaluationResult, OverflowError> {
561557
debug!("evaluate_trait_predicate_recursively({:?})", obligation);
562558

563-
if self.intercrate.is_none()
559+
if !self.intercrate
564560
&& obligation.is_global()
565561
&& obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst())
566562
{
@@ -725,7 +721,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
725721
stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh());
726722
// This check was an imperfect workaround for a bug in the old
727723
// intercrate mode; it should be removed when that goes away.
728-
if unbound_input_types && self.intercrate == Some(IntercrateMode::Issue43355) {
724+
if unbound_input_types && self.intercrate {
729725
debug!(
730726
"evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous",
731727
stack.fresh_trait_ref
@@ -1204,7 +1200,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12041200
fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
12051201
debug!("is_knowable(intercrate={:?})", self.intercrate);
12061202

1207-
if !self.intercrate.is_some() {
1203+
if !self.intercrate {
12081204
return None;
12091205
}
12101206

@@ -1216,17 +1212,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12161212
// bound regions.
12171213
let trait_ref = predicate.skip_binder().trait_ref;
12181214

1219-
let result = coherence::trait_ref_is_knowable(self.tcx(), trait_ref);
1220-
if let (
1221-
Some(Conflict::Downstream { used_to_be_broken: true }),
1222-
Some(IntercrateMode::Issue43355),
1223-
) = (result, self.intercrate)
1224-
{
1225-
debug!("is_knowable: IGNORING conflict to be bug-compatible with #43355");
1226-
None
1227-
} else {
1228-
result
1229-
}
1215+
coherence::trait_ref_is_knowable(self.tcx(), trait_ref)
12301216
}
12311217

12321218
/// Returns `true` if the global caches can be used.
@@ -1247,7 +1233,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12471233
// the master cache. Since coherence executes pretty quickly,
12481234
// it's not worth going to more trouble to increase the
12491235
// hit-rate, I don't think.
1250-
if self.intercrate.is_some() {
1236+
if self.intercrate {
12511237
return false;
12521238
}
12531239

@@ -3303,7 +3289,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
33033289
return Err(());
33043290
}
33053291

3306-
if self.intercrate.is_none()
3292+
if !self.intercrate
33073293
&& self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
33083294
{
33093295
debug!("match_impl: reservation impls only apply in intercrate mode");

src/librustc/traits/specialize/mod.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -332,14 +332,9 @@ pub(super) fn specialization_graph_provider(
332332
let impl_span =
333333
tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap());
334334
let mut err = match used_to_be_allowed {
335-
Some(FutureCompatOverlapErrorKind::Issue43355) | None => {
336-
struct_span_err!(tcx.sess, impl_span, E0119, "{}", msg)
337-
}
335+
None => struct_span_err!(tcx.sess, impl_span, E0119, "{}", msg),
338336
Some(kind) => {
339337
let lint = match kind {
340-
FutureCompatOverlapErrorKind::Issue43355 => {
341-
unreachable!("converted to hard error above")
342-
}
343338
FutureCompatOverlapErrorKind::Issue33140 => {
344339
ORDER_DEPENDENT_TRAIT_OBJECTS
345340
}

src/librustc/traits/specialize/specialization_graph.rs

+1-20
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ pub use rustc::traits::types::specialization_graph::*;
99

1010
#[derive(Copy, Clone, Debug)]
1111
pub enum FutureCompatOverlapErrorKind {
12-
Issue43355,
1312
Issue33140,
1413
LeakCheck,
1514
}
@@ -111,7 +110,6 @@ impl<'tcx> Children {
111110
tcx,
112111
possible_sibling,
113112
impl_def_id,
114-
traits::IntercrateMode::Issue43355,
115113
traits::SkipLeakCheck::default(),
116114
|overlap| {
117115
if let Some(overlap_kind) =
@@ -155,30 +153,13 @@ impl<'tcx> Children {
155153
replace_children.push(possible_sibling);
156154
} else {
157155
if let None = tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
158-
// do future-compat checks for overlap. Have issue #33140
159-
// errors overwrite issue #43355 errors when both are present.
160-
161-
traits::overlapping_impls(
162-
tcx,
163-
possible_sibling,
164-
impl_def_id,
165-
traits::IntercrateMode::Fixed,
166-
traits::SkipLeakCheck::default(),
167-
|overlap| {
168-
last_lint = Some(FutureCompatOverlapError {
169-
error: overlap_error(overlap),
170-
kind: FutureCompatOverlapErrorKind::Issue43355,
171-
});
172-
},
173-
|| (),
174-
);
156+
// Do future-compat checks for overlap.
175157

176158
if last_lint.is_none() {
177159
traits::overlapping_impls(
178160
tcx,
179161
possible_sibling,
180162
impl_def_id,
181-
traits::IntercrateMode::Fixed,
182163
traits::SkipLeakCheck::Yes,
183164
|overlap| {
184165
last_lint = Some(FutureCompatOverlapError {

src/librustc_typeck/coherence/builtin.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,12 @@ use rustc_hir::def_id::DefId;
1818
use rustc_hir::ItemKind;
1919

2020
pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
21+
let lang_items = tcx.lang_items();
2122
Checker { tcx, trait_def_id }
22-
.check(tcx.lang_items().drop_trait(), visit_implementation_of_drop)
23-
.check(tcx.lang_items().copy_trait(), visit_implementation_of_copy)
24-
.check(tcx.lang_items().coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
25-
.check(
26-
tcx.lang_items().dispatch_from_dyn_trait(),
27-
visit_implementation_of_dispatch_from_dyn,
28-
);
23+
.check(lang_items.drop_trait(), visit_implementation_of_drop)
24+
.check(lang_items.copy_trait(), visit_implementation_of_copy)
25+
.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
26+
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
2927
}
3028

3129
struct Checker<'tcx> {

src/librustc_typeck/coherence/inherent_impls_overlap.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::namespace::Namespace;
2-
use rustc::traits::{self, IntercrateMode, SkipLeakCheck};
2+
use rustc::traits::{self, SkipLeakCheck};
33
use rustc::ty::TyCtxt;
44
use rustc_errors::struct_span_err;
55
use rustc_hir as hir;
@@ -75,7 +75,6 @@ impl InherentOverlapChecker<'tcx> {
7575
self.tcx,
7676
impl1_def_id,
7777
impl2_def_id,
78-
IntercrateMode::Issue43355,
7978
// We go ahead and just skip the leak check for
8079
// inherent impls without warning.
8180
SkipLeakCheck::Yes,

0 commit comments

Comments
 (0)