@@ -10,6 +10,7 @@ use rustc_type_ir::{
10
10
} ;
11
11
use tracing:: { debug, instrument} ;
12
12
13
+ use super :: has_only_region_constraints;
13
14
use super :: trait_goals:: TraitGoalProvenVia ;
14
15
use crate :: delegate:: SolverDelegate ;
15
16
use crate :: solve:: inspect:: ProbeKind ;
@@ -771,6 +772,69 @@ where
771
772
}
772
773
} )
773
774
}
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
+ }
774
838
775
839
/// Assemble and merge candidates for goals which are related to an underlying trait
776
840
/// goal. Right now, this is normalizes-to and host effect goals.
@@ -857,7 +921,7 @@ where
857
921
}
858
922
}
859
923
TraitGoalProvenVia :: Misc => {
860
- let candidates =
924
+ let mut candidates =
861
925
self . assemble_and_evaluate_candidates ( goal, AssembleCandidatesFrom :: All ) ;
862
926
863
927
// Prefer "orphaned" param-env normalization predicates, which are used
@@ -871,6 +935,13 @@ where
871
935
return Ok ( response) ;
872
936
}
873
937
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
+
874
945
let responses: Vec < _ > = candidates. iter ( ) . map ( |c| c. result ) . collect ( ) ;
875
946
if let Some ( response) = self . try_merge_responses ( & responses) {
876
947
Ok ( response)
0 commit comments