Skip to content

Commit

Permalink
Auto merge of rust-lang#95333 - GuillaumeGomez:auto-trait-perf-issue,…
Browse files Browse the repository at this point in the history
… r=oli-obk

Fix perf issue for auto trait selection

Follow-up of rust-lang#95069 which fixes the perf issue introduced by it.

r? `@oli-obk`
  • Loading branch information
bors committed Mar 28, 2022
2 parents 6252304 + bd51f17 commit 3badf5c
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 28 deletions.
9 changes: 9 additions & 0 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,15 @@ impl<'tcx> PolyTraitRef<'tcx> {
polarity: ty::ImplPolarity::Positive,
})
}

/// Same as [`PolyTraitRef::to_poly_trait_predicate`] but sets a negative polarity instead.
pub fn to_poly_trait_predicate_negative_polarity(&self) -> ty::PolyTraitPredicate<'tcx> {
self.map_bound(|trait_ref| ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
polarity: ty::ImplPolarity::Negative,
})
}
}

/// An existential reference to a trait, where `Self` is erased.
Expand Down
22 changes: 20 additions & 2 deletions compiler/rustc_trait_selection/src/traits/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,31 @@ impl<'tcx> AutoTraitFinder<'tcx> {
let trait_pred = ty::Binder::dummy(trait_ref);

let bail_out = tcx.infer_ctxt().enter(|infcx| {
let mut selcx = SelectionContext::with_negative(&infcx, true);
let mut selcx = SelectionContext::new(&infcx);
let result = selcx.select(&Obligation::new(
ObligationCause::dummy(),
orig_env,
trait_pred.to_poly_trait_predicate(),
));

match result {
Ok(Some(ImplSource::UserDefined(_))) => {
debug!(
"find_auto_trait_generics({:?}): \
manual impl found, bailing out",
trait_ref
);
return true;
}
_ => {}
}

let result = selcx.select(&Obligation::new(
ObligationCause::dummy(),
orig_env,
trait_pred.to_poly_trait_predicate_negative_polarity(),
));

match result {
Ok(Some(ImplSource::UserDefined(_))) => {
debug!(
Expand Down Expand Up @@ -277,7 +295,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
fresh_preds.insert(self.clean_pred(infcx, predicate));
}

let mut select = SelectionContext::with_negative(&infcx, true);
let mut select = SelectionContext::new(&infcx);

let mut already_visited = FxHashSet::default();
let mut predicates = VecDeque::new();
Expand Down
28 changes: 2 additions & 26 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,6 @@ pub struct SelectionContext<'cx, 'tcx> {

intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,

/// Controls whether or not to filter out negative impls when selecting.
/// This is used in librustdoc to distinguish between the lack of an impl
/// and a negative impl
allow_negative_impls: bool,

/// The mode that trait queries run in, which informs our error handling
/// policy. In essence, canonicalized queries need their errors propagated
/// rather than immediately reported because we do not have accurate spans.
Expand Down Expand Up @@ -215,7 +210,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
freshener: infcx.freshener_keep_static(),
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
query_mode: TraitQueryMode::Standard,
}
}
Expand All @@ -226,22 +220,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
freshener: infcx.freshener_keep_static(),
intercrate: true,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
query_mode: TraitQueryMode::Standard,
}
}

pub fn with_negative(
infcx: &'cx InferCtxt<'cx, 'tcx>,
allow_negative_impls: bool,
) -> SelectionContext<'cx, 'tcx> {
debug!(?allow_negative_impls, "with_negative");
SelectionContext {
infcx,
freshener: infcx.freshener_keep_static(),
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls,
query_mode: TraitQueryMode::Standard,
}
}
Expand All @@ -256,7 +234,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
freshener: infcx.freshener_keep_static(),
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
query_mode,
}
}
Expand Down Expand Up @@ -1192,7 +1169,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let ImplCandidate(def_id) = candidate {
if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id)
|| obligation.polarity() == tcx.impl_polarity(def_id)
|| self.allow_negative_impls
{
result.push(candidate);
}
Expand Down Expand Up @@ -1272,7 +1248,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// the master cache. Since coherence executes pretty quickly,
// it's not worth going to more trouble to increase the
// hit-rate, I don't think.
if self.intercrate || self.allow_negative_impls {
if self.intercrate {
return false;
}

Expand All @@ -1289,7 +1265,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// mode, so don't do any caching. In particular, we might
// re-use the same `InferCtxt` with both an intercrate
// and non-intercrate `SelectionContext`
if self.intercrate || self.allow_negative_impls {
if self.intercrate {
return None;
}
let tcx = self.tcx();
Expand Down

0 comments on commit 3badf5c

Please sign in to comment.