@@ -10,6 +10,7 @@ use rustc_type_ir::{
1010} ;
1111use tracing:: { debug, instrument} ;
1212
13+ use super :: has_only_region_constraints;
1314use super :: trait_goals:: TraitGoalProvenVia ;
1415use crate :: delegate:: SolverDelegate ;
1516use crate :: solve:: inspect:: ProbeKind ;
@@ -771,6 +772,69 @@ where
771772 }
772773 } )
773774 }
775+ }
776+
777+ pub ( super ) enum AllowInferenceConstraints {
778+ Yes ,
779+ No ,
780+ }
781+
782+ impl < D , I > EvalCtxt < ' _ , D >
783+ where
784+ D : SolverDelegate < Interner = I > ,
785+ I : Interner ,
786+ {
787+ /// Check whether we can ignore impl candidates due to specialization.
788+ ///
789+ /// This is only necessary for `feature(specialization)` and seems quite ugly.
790+ pub ( super ) fn filter_specialized_impls (
791+ & mut self ,
792+ allow_inference_constraints : AllowInferenceConstraints ,
793+ candidates : & mut Vec < Candidate < I > > ,
794+ ) {
795+ match self . typing_mode ( ) {
796+ TypingMode :: Coherence => return ,
797+ TypingMode :: Analysis { .. }
798+ | TypingMode :: Borrowck { .. }
799+ | TypingMode :: PostBorrowckAnalysis { .. }
800+ | TypingMode :: PostAnalysis => { }
801+ }
802+
803+ let mut i = 0 ;
804+ ' outer: while i < candidates. len ( ) {
805+ let CandidateSource :: Impl ( victim_def_id) = candidates[ i] . source else {
806+ i += 1 ;
807+ continue ;
808+ } ;
809+
810+ for ( j, c) in candidates. iter ( ) . enumerate ( ) {
811+ if i == j {
812+ continue ;
813+ }
814+
815+ let CandidateSource :: Impl ( other_def_id) = c. source else {
816+ continue ;
817+ } ;
818+
819+ // See if we can toss out `victim` based on specialization.
820+ //
821+ // While this requires us to know *for sure* that the `lhs` impl applies
822+ // we still use modulo regions here. This is fine as specialization currently
823+ // assumes that specializing impls have to be always applicable, meaning that
824+ // the only allowed region constraints may be constraints also present on the default impl.
825+ if matches ! ( allow_inference_constraints, AllowInferenceConstraints :: Yes )
826+ || has_only_region_constraints ( c. result )
827+ {
828+ if self . cx ( ) . impl_specializes ( other_def_id, victim_def_id) {
829+ candidates. remove ( i) ;
830+ continue ' outer;
831+ }
832+ }
833+ }
834+
835+ i += 1 ;
836+ }
837+ }
774838
775839 /// Assemble and merge candidates for goals which are related to an underlying trait
776840 /// goal. Right now, this is normalizes-to and host effect goals.
@@ -857,7 +921,7 @@ where
857921 }
858922 }
859923 TraitGoalProvenVia :: Misc => {
860- let candidates =
924+ let mut candidates =
861925 self . assemble_and_evaluate_candidates ( goal, AssembleCandidatesFrom :: All ) ;
862926
863927 // Prefer "orphaned" param-env normalization predicates, which are used
@@ -871,6 +935,13 @@ where
871935 return Ok ( response) ;
872936 }
873937
938+ // We drop specialized impls to allow normalization via a final impl here. In case
939+ // the specializing impl has different inference constraints from the specialized
940+ // impl, proving the trait goal is already ambiguous, so we never get here. This
941+ // means we can just ignore inference constraints and don't have to special-case
942+ // constraining the normalized-to `term`.
943+ self . filter_specialized_impls ( AllowInferenceConstraints :: Yes , & mut candidates) ;
944+
874945 let responses: Vec < _ > = candidates. iter ( ) . map ( |c| c. result ) . collect ( ) ;
875946 if let Some ( response) = self . try_merge_responses ( & responses) {
876947 Ok ( response)
0 commit comments