Skip to content

Commit b3cfb97

Browse files
authored
Rollup merge of #68966 - jonas-schievink:coherence-perf, r=varkor
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 that effectively runs the expensive parts of coherence *twice*, which can even be visualized by obtaining a flamegraph: ![image](https://user-images.githubusercontent.com/5047365/74091959-e1f41200-4a8b-11ea-969d-2849d3f86c63.png)
2 parents 8007f84 + 2309592 commit b3cfb97

File tree

10 files changed

+81
-136
lines changed

10 files changed

+81
-136
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
@@ -78,13 +78,6 @@ pub use self::chalk_fulfill::{
7878

7979
pub use self::types::*;
8080

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

src/librustc/traits/select.rs

+15-29
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ use super::DerivedObligationCause;
1919
use super::Selection;
2020
use super::SelectionResult;
2121
use super::TraitNotObjectSafe;
22+
use super::TraitQueryMode;
2223
use super::{BuiltinDerivedObligation, ImplDerivedObligation, ObligationCauseCode};
23-
use super::{IntercrateMode, TraitQueryMode};
2424
use super::{ObjectCastObligation, Obligation};
2525
use super::{ObligationCause, PredicateObligation, TraitObligation};
2626
use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented};
@@ -80,7 +80,7 @@ pub struct SelectionContext<'cx, 'tcx> {
8080
/// other words, we consider `$0: Bar` to be unimplemented if
8181
/// there is no type that the user could *actually name* that
8282
/// would satisfy it. This avoids crippling inference, basically.
83-
intercrate: Option<IntercrateMode>,
83+
intercrate: bool,
8484

8585
intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
8686

@@ -218,22 +218,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
218218
SelectionContext {
219219
infcx,
220220
freshener: infcx.freshener(),
221-
intercrate: None,
221+
intercrate: false,
222222
intercrate_ambiguity_causes: None,
223223
allow_negative_impls: false,
224224
query_mode: TraitQueryMode::Standard,
225225
}
226226
}
227227

228-
pub fn intercrate(
229-
infcx: &'cx InferCtxt<'cx, 'tcx>,
230-
mode: IntercrateMode,
231-
) -> SelectionContext<'cx, 'tcx> {
232-
debug!("intercrate({:?})", mode);
228+
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
233229
SelectionContext {
234230
infcx,
235231
freshener: infcx.freshener(),
236-
intercrate: Some(mode),
232+
intercrate: true,
237233
intercrate_ambiguity_causes: None,
238234
allow_negative_impls: false,
239235
query_mode: TraitQueryMode::Standard,
@@ -248,7 +244,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
248244
SelectionContext {
249245
infcx,
250246
freshener: infcx.freshener(),
251-
intercrate: None,
247+
intercrate: false,
252248
intercrate_ambiguity_causes: None,
253249
allow_negative_impls,
254250
query_mode: TraitQueryMode::Standard,
@@ -263,7 +259,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
263259
SelectionContext {
264260
infcx,
265261
freshener: infcx.freshener(),
266-
intercrate: None,
262+
intercrate: false,
267263
intercrate_ambiguity_causes: None,
268264
allow_negative_impls: false,
269265
query_mode,
@@ -276,7 +272,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
276272
/// false overflow results (#47139) and because it costs
277273
/// computation time.
278274
pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
279-
assert!(self.intercrate.is_some());
275+
assert!(self.intercrate);
280276
assert!(self.intercrate_ambiguity_causes.is_none());
281277
self.intercrate_ambiguity_causes = Some(vec![]);
282278
debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
@@ -286,7 +282,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
286282
/// was enabled and disables tracking at the same time. If
287283
/// tracking is not enabled, just returns an empty vector.
288284
pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> {
289-
assert!(self.intercrate.is_some());
285+
assert!(self.intercrate);
290286
self.intercrate_ambiguity_causes.take().unwrap_or(vec![])
291287
}
292288

@@ -562,7 +558,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
562558
) -> Result<EvaluationResult, OverflowError> {
563559
debug!("evaluate_trait_predicate_recursively({:?})", obligation);
564560

565-
if self.intercrate.is_none()
561+
if !self.intercrate
566562
&& obligation.is_global()
567563
&& obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst())
568564
{
@@ -727,7 +723,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
727723
stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh());
728724
// This check was an imperfect workaround for a bug in the old
729725
// intercrate mode; it should be removed when that goes away.
730-
if unbound_input_types && self.intercrate == Some(IntercrateMode::Issue43355) {
726+
if unbound_input_types && self.intercrate {
731727
debug!(
732728
"evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous",
733729
stack.fresh_trait_ref
@@ -1206,7 +1202,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12061202
fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
12071203
debug!("is_knowable(intercrate={:?})", self.intercrate);
12081204

1209-
if !self.intercrate.is_some() {
1205+
if !self.intercrate {
12101206
return None;
12111207
}
12121208

@@ -1218,17 +1214,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12181214
// bound regions.
12191215
let trait_ref = predicate.skip_binder().trait_ref;
12201216

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

12341220
/// Returns `true` if the global caches can be used.
@@ -1249,7 +1235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12491235
// the master cache. Since coherence executes pretty quickly,
12501236
// it's not worth going to more trouble to increase the
12511237
// hit-rate, I don't think.
1252-
if self.intercrate.is_some() {
1238+
if self.intercrate {
12531239
return false;
12541240
}
12551241

@@ -3305,7 +3291,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
33053291
return Err(());
33063292
}
33073293

3308-
if self.intercrate.is_none()
3294+
if !self.intercrate
33093295
&& self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
33103296
{
33113297
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

+6-24
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
}
@@ -107,16 +106,16 @@ impl<'tcx> Children {
107106
}
108107
};
109108

109+
let allowed_to_overlap =
110+
tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling);
111+
110112
let (le, ge) = traits::overlapping_impls(
111113
tcx,
112114
possible_sibling,
113115
impl_def_id,
114-
traits::IntercrateMode::Issue43355,
115116
traits::SkipLeakCheck::default(),
116117
|overlap| {
117-
if let Some(overlap_kind) =
118-
tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
119-
{
118+
if let Some(overlap_kind) = &allowed_to_overlap {
120119
match overlap_kind {
121120
ty::ImplOverlapKind::Permitted { marker: _ } => {}
122121
ty::ImplOverlapKind::Issue33140 => {
@@ -154,31 +153,14 @@ impl<'tcx> Children {
154153

155154
replace_children.push(possible_sibling);
156155
} else {
157-
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+
if let None = allowed_to_overlap {
157+
// Do future-compat checks for overlap.
175158

176159
if last_lint.is_none() {
177160
traits::overlapping_impls(
178161
tcx,
179162
possible_sibling,
180163
impl_def_id,
181-
traits::IntercrateMode::Fixed,
182164
traits::SkipLeakCheck::Yes,
183165
|overlap| {
184166
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::{AssocItem, TyCtxt};
44
use rustc_errors::struct_span_err;
55
use rustc_hir as hir;
@@ -93,7 +93,6 @@ impl InherentOverlapChecker<'tcx> {
9393
self.tcx,
9494
impl1_def_id,
9595
impl2_def_id,
96-
IntercrateMode::Issue43355,
9796
// We go ahead and just skip the leak check for
9897
// inherent impls without warning.
9998
SkipLeakCheck::Yes,

0 commit comments

Comments
 (0)