6
6
//!
7
7
//! [rustc dev guide]:
8
8
//! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
9
+ use rustc_ast:: Mutability ;
9
10
use rustc_data_structures:: stack:: ensure_sufficient_stack;
10
11
use rustc_hir:: lang_items:: LangItem ;
11
12
use rustc_infer:: infer:: LateBoundRegionConversionTime :: HigherRankedType ;
12
13
use rustc_infer:: infer:: { DefineOpaqueTypes , InferOk } ;
13
14
use rustc_middle:: traits:: SelectionOutputTypeParameterMismatch ;
14
15
use rustc_middle:: ty:: {
15
16
self , Binder , GenericParamDefKind , InternalSubsts , SubstsRef , ToPolyTraitRef , ToPredicate ,
16
- TraitRef , Ty , TyCtxt , TypeVisitableExt ,
17
+ TraitPredicate , TraitRef , Ty , TyCtxt , TypeVisitableExt ,
17
18
} ;
18
19
use rustc_session:: config:: TraitSolver ;
19
20
use rustc_span:: def_id:: DefId ;
@@ -279,11 +280,60 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
279
280
ImplSourceBuiltinData { nested : obligations }
280
281
}
281
282
283
+ #[ instrument( level = "debug" , skip( self ) ) ]
282
284
fn confirm_transmutability_candidate (
283
285
& mut self ,
284
286
obligation : & TraitObligation < ' tcx > ,
285
287
) -> Result < ImplSourceBuiltinData < PredicateObligation < ' tcx > > , SelectionError < ' tcx > > {
286
- debug ! ( ?obligation, "confirm_transmutability_candidate" ) ;
288
+ use rustc_transmute:: { Answer , Condition } ;
289
+ #[ instrument( level = "debug" , skip( tcx, obligation, predicate) ) ]
290
+ fn flatten_answer_tree < ' tcx > (
291
+ tcx : TyCtxt < ' tcx > ,
292
+ obligation : & TraitObligation < ' tcx > ,
293
+ predicate : TraitPredicate < ' tcx > ,
294
+ cond : Condition < rustc_transmute:: layout:: rustc:: Ref < ' tcx > > ,
295
+ ) -> Vec < PredicateObligation < ' tcx > > {
296
+ match cond {
297
+ // FIXME(bryangarza): Add separate `IfAny` case, instead of treating as `IfAll`
298
+ // Not possible until the trait solver supports disjunctions of obligations
299
+ Condition :: IfAll ( conds) | Condition :: IfAny ( conds) => conds
300
+ . into_iter ( )
301
+ . flat_map ( |cond| flatten_answer_tree ( tcx, obligation, predicate, cond) )
302
+ . collect ( ) ,
303
+ Condition :: IfTransmutable { src, dst } => {
304
+ let trait_def_id = obligation. predicate . def_id ( ) ;
305
+ let scope = predicate. trait_ref . substs . type_at ( 2 ) ;
306
+ let assume_const = predicate. trait_ref . substs . const_at ( 3 ) ;
307
+ let make_obl = |from_ty, to_ty| {
308
+ let trait_ref1 = ty:: TraitRef :: new (
309
+ tcx,
310
+ trait_def_id,
311
+ [
312
+ ty:: GenericArg :: from ( to_ty) ,
313
+ ty:: GenericArg :: from ( from_ty) ,
314
+ ty:: GenericArg :: from ( scope) ,
315
+ ty:: GenericArg :: from ( assume_const) ,
316
+ ] ,
317
+ ) ;
318
+ Obligation :: with_depth (
319
+ tcx,
320
+ obligation. cause . clone ( ) ,
321
+ obligation. recursion_depth + 1 ,
322
+ obligation. param_env ,
323
+ trait_ref1,
324
+ )
325
+ } ;
326
+
327
+ // If Dst is mutable, check bidirectionally.
328
+ // For example, transmuting bool -> u8 is OK as long as you can't update that u8
329
+ // to be > 1, because you could later transmute the u8 back to a bool and get UB.
330
+ match dst. mutability {
331
+ Mutability :: Not => vec ! [ make_obl( src. ty, dst. ty) ] ,
332
+ Mutability :: Mut => vec ! [ make_obl( src. ty, dst. ty) , make_obl( dst. ty, src. ty) ] ,
333
+ }
334
+ }
335
+ }
336
+ }
287
337
288
338
// We erase regions here because transmutability calls layout queries,
289
339
// which does not handle inference regions and doesn't particularly
@@ -301,21 +351,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
301
351
return Err ( Unimplemented ) ;
302
352
} ;
303
353
354
+ let dst = predicate. trait_ref . substs . type_at ( 0 ) ;
355
+ let src = predicate. trait_ref . substs . type_at ( 1 ) ;
356
+ debug ! ( ?src, ?dst) ;
304
357
let mut transmute_env = rustc_transmute:: TransmuteTypeEnv :: new ( self . infcx ) ;
305
358
let maybe_transmutable = transmute_env. is_transmutable (
306
359
obligation. cause . clone ( ) ,
307
- rustc_transmute:: Types {
308
- dst : predicate. trait_ref . substs . type_at ( 0 ) ,
309
- src : predicate. trait_ref . substs . type_at ( 1 ) ,
310
- } ,
360
+ rustc_transmute:: Types { dst, src } ,
311
361
predicate. trait_ref . substs . type_at ( 2 ) ,
312
362
assume,
313
363
) ;
314
364
315
- match maybe_transmutable {
316
- rustc_transmute:: Answer :: Yes => Ok ( ImplSourceBuiltinData { nested : vec ! [ ] } ) ,
317
- _ => Err ( Unimplemented ) ,
318
- }
365
+ let fully_flattened = match maybe_transmutable {
366
+ Answer :: No ( _) => Err ( Unimplemented ) ?,
367
+ Answer :: If ( cond) => flatten_answer_tree ( self . tcx ( ) , obligation, predicate, cond) ,
368
+ Answer :: Yes => vec ! [ ] ,
369
+ } ;
370
+
371
+ debug ! ( ?fully_flattened) ;
372
+ Ok ( ImplSourceBuiltinData { nested : fully_flattened } )
319
373
}
320
374
321
375
/// This handles the case where an `auto trait Foo` impl is being used.
0 commit comments