@@ -9,15 +9,15 @@ use rustc_type_ir::{
9
9
self as ty, Interner , Movability , TraitPredicate , TypeVisitableExt as _, TypingMode ,
10
10
Upcast as _, elaborate,
11
11
} ;
12
- use tracing:: { instrument, trace} ;
12
+ use tracing:: { debug , instrument, trace} ;
13
13
14
14
use crate :: delegate:: SolverDelegate ;
15
15
use crate :: solve:: assembly:: structural_traits:: { self , AsyncCallableRelevantTypes } ;
16
16
use crate :: solve:: assembly:: { self , AllowInferenceConstraints , AssembleCandidatesFrom , Candidate } ;
17
17
use crate :: solve:: inspect:: ProbeKind ;
18
18
use crate :: solve:: {
19
19
BuiltinImplSource , CandidateSource , Certainty , EvalCtxt , Goal , GoalSource , MaybeCause ,
20
- NoSolution , ParamEnvSource , QueryResult ,
20
+ NoSolution , ParamEnvSource , QueryResult , has_only_region_constraints ,
21
21
} ;
22
22
23
23
impl < D , I > assembly:: GoalKind < D > for TraitPredicate < I >
@@ -1253,6 +1253,45 @@ where
1253
1253
D : SolverDelegate < Interner = I > ,
1254
1254
I : Interner ,
1255
1255
{
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
+
1256
1295
#[ instrument( level = "debug" , skip( self ) , ret) ]
1257
1296
pub ( super ) fn merge_trait_candidates (
1258
1297
& mut self ,
@@ -1313,6 +1352,7 @@ where
1313
1352
}
1314
1353
1315
1354
self . filter_specialized_impls ( AllowInferenceConstraints :: No , & mut candidates) ;
1355
+ self . unsound_prefer_builtin_dyn_impl ( & mut candidates) ;
1316
1356
1317
1357
// If there are *only* global where bounds, then make sure to return that this
1318
1358
// is still reported as being proven-via the param-env so that rigid projections
0 commit comments