diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src')
4 files changed, 69 insertions, 6 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 93c7dae9c5b..81893cdcc7e 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -462,6 +462,7 @@ fn impl_intersection_has_negative_obligation( let param_env = infcx.resolve_vars_if_possible(param_env); util::elaborate(tcx, tcx.predicates_of(impl2_def_id).instantiate(tcx, impl2_header.impl_args)) + .elaborate_sized() .any(|(clause, _)| try_prove_negated_where_clause(infcx, clause, param_env)) } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index b7be73a3c2b..81ce58a93fa 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -215,6 +215,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } selcx.infcx.probe(|_| { + let bound = util::lazily_elaborate_sizedness_candidate( + selcx.infcx, + obligation, + bound, + ); + // We checked the polarity already match selcx.match_normalize_trait_ref( obligation, @@ -259,14 +265,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .caller_bounds() .iter() .filter_map(|p| p.as_trait_clause()) - // Micro-optimization: filter out predicates relating to different traits. - .filter(|p| p.def_id() == stack.obligation.predicate.def_id()) + // Micro-optimization: filter out predicates with different polarities. .filter(|p| p.polarity() == stack.obligation.predicate.polarity()); let drcx = DeepRejectCtxt::relate_rigid_rigid(self.tcx()); let obligation_args = stack.obligation.predicate.skip_binder().trait_ref.args; // Keep only those bounds which may apply, and propagate overflow if it occurs. for bound in bounds { + let bound = + util::lazily_elaborate_sizedness_candidate(self.infcx, stack.obligation, bound); + + // Micro-optimization: filter out predicates relating to different traits. + if bound.def_id() != stack.obligation.predicate.def_id() { + continue; + } + let bound_trait_ref = bound.map_bound(|t| t.trait_ref); if !drcx.args_may_unify(obligation_args, bound_trait_ref.skip_binder().args) { continue; diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index b2d2f1188c3..80f71c78993 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -166,10 +166,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) .break_value() .expect("expected to index into clause that exists"); - let candidate = candidate_predicate + let candidate_predicate = candidate_predicate .as_trait_clause() - .expect("projection candidate is not a trait predicate") - .map_bound(|t| t.trait_ref); + .expect("projection candidate is not a trait predicate"); + let candidate_predicate = + util::lazily_elaborate_sizedness_candidate(self.infcx, obligation, candidate_predicate); + + let candidate = candidate_predicate.map_bound(|t| t.trait_ref); let candidate = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, @@ -226,6 +229,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> PredicateObligations<'tcx> { debug!(?obligation, ?param, "confirm_param_candidate"); + let param = util::lazily_elaborate_sizedness_candidate( + self.infcx, + obligation, + param.upcast(self.infcx.tcx), + ) + .map_bound(|p| p.trait_ref); + // During evaluation, we already checked that this // where-clause trait-ref could be unified with the obligation // trait-ref. Repeat that unification now without any diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index bf2cbe7c047..a05bae53566 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -4,10 +4,13 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir::LangItem; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::PolyTraitObligation; pub use rustc_infer::traits::util::*; use rustc_middle::bug; +use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{ - self, SizedTraitKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + self, PolyTraitPredicate, SizedTraitKind, TraitPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, + TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; pub use rustc_next_trait_solver::placeholder::BoundVarReplacer; use rustc_span::Span; @@ -382,3 +385,39 @@ pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc false } + +/// To improve performance, sizedness traits are not elaborated and so special-casing is required +/// in the trait solver to find a `Sized` candidate for a `MetaSized` obligation. Returns the +/// predicate to used in the candidate for such a `obligation`, given a `candidate`. +pub(crate) fn lazily_elaborate_sizedness_candidate<'tcx>( + infcx: &InferCtxt<'tcx>, + obligation: &PolyTraitObligation<'tcx>, + candidate: PolyTraitPredicate<'tcx>, +) -> PolyTraitPredicate<'tcx> { + if !infcx.tcx.is_lang_item(obligation.predicate.def_id(), LangItem::MetaSized) + || !infcx.tcx.is_lang_item(candidate.def_id(), LangItem::Sized) + { + return candidate; + } + + if obligation.predicate.polarity() != candidate.polarity() { + return candidate; + } + + let drcx = DeepRejectCtxt::relate_rigid_rigid(infcx.tcx); + if !drcx.args_may_unify( + obligation.predicate.skip_binder().trait_ref.args, + candidate.skip_binder().trait_ref.args, + ) { + return candidate; + } + + candidate.map_bound(|c| TraitPredicate { + trait_ref: TraitRef::new_from_args( + infcx.tcx, + obligation.predicate.def_id(), + c.trait_ref.args, + ), + polarity: c.polarity, + }) +} |
