@@ -9,15 +9,15 @@ use rustc_type_ir::{
99 self as ty, Interner , Movability , TraitPredicate , TypeVisitableExt as _, TypingMode ,
1010 Upcast as _, elaborate,
1111} ;
12- use tracing:: { instrument, trace} ;
12+ use tracing:: { debug , instrument, trace} ;
1313
1414use crate :: delegate:: SolverDelegate ;
1515use crate :: solve:: assembly:: structural_traits:: { self , AsyncCallableRelevantTypes } ;
1616use crate :: solve:: assembly:: { self , AllowInferenceConstraints , AssembleCandidatesFrom , Candidate } ;
1717use crate :: solve:: inspect:: ProbeKind ;
1818use crate :: solve:: {
1919 BuiltinImplSource , CandidateSource , Certainty , EvalCtxt , Goal , GoalSource , MaybeCause ,
20- NoSolution , ParamEnvSource , QueryResult ,
20+ NoSolution , ParamEnvSource , QueryResult , has_only_region_constraints ,
2121} ;
2222
2323impl < D , I > assembly:: GoalKind < D > for TraitPredicate < I >
@@ -1253,6 +1253,45 @@ where
12531253 D : SolverDelegate < Interner = I > ,
12541254 I : Interner ,
12551255{
1256+ /// FIXME(#57893): For backwards compatability with the old trait solver implementation,
1257+ /// we need to handle overlap between builtin and user-written impls for trait objects.
1258+ ///
1259+ /// This overlap is unsound in general and something which we intend to fix separately.
1260+ /// To avoid blocking the stabilization of the trait solver, we add this hack to avoid
1261+ /// breakage in cases which are *mostly fine*™. Importantly, this preference is strictly
1262+ /// weaker than the old behavior.
1263+ ///
1264+ /// We only prefer builtin over user-written impls if there are no inference constraints.
1265+ /// Importantly, we also only prefer the builtin impls for trait goals, and not during
1266+ /// normalization. This means the only case where this special-case results in exploitable
1267+ /// unsoundness should be lifetime dependent user-written impls.
1268+ pub ( super ) fn unsound_prefer_builtin_dyn_impl ( & mut self , candidates : & mut Vec < Candidate < I > > ) {
1269+ match self . typing_mode ( ) {
1270+ TypingMode :: Coherence => return ,
1271+ TypingMode :: Analysis { .. }
1272+ | TypingMode :: Borrowck { .. }
1273+ | TypingMode :: PostBorrowckAnalysis { .. }
1274+ | TypingMode :: PostAnalysis => { }
1275+ }
1276+
1277+ if candidates
1278+ . iter ( )
1279+ . find ( |c| {
1280+ matches ! ( c. source, CandidateSource :: BuiltinImpl ( BuiltinImplSource :: Object ( _) ) )
1281+ } )
1282+ . is_some_and ( |c| has_only_region_constraints ( c. result ) )
1283+ {
1284+ candidates. retain ( |c| {
1285+ if matches ! ( c. source, CandidateSource :: Impl ( _) ) {
1286+ debug ! ( ?c, "unsoundly dropping impl in favor of builtin dyn-candidate" ) ;
1287+ false
1288+ } else {
1289+ true
1290+ }
1291+ } ) ;
1292+ }
1293+ }
1294+
12561295 #[ instrument( level = "debug" , skip( self ) , ret) ]
12571296 pub ( super ) fn merge_trait_candidates (
12581297 & mut self ,
@@ -1313,6 +1352,7 @@ where
13131352 }
13141353
13151354 self . filter_specialized_impls ( AllowInferenceConstraints :: No , & mut candidates) ;
1355+ self . unsound_prefer_builtin_dyn_impl ( & mut candidates) ;
13161356
13171357 // If there are *only* global where bounds, then make sure to return that this
13181358 // is still reported as being proven-via the param-env so that rigid projections
0 commit comments