@@ -9,6 +9,7 @@ fn main() {
9
9
drop_principal ( ) ;
10
10
modulo_binder ( ) ;
11
11
modulo_assoc ( ) ;
12
+ bidirectional_subtyping ( ) ;
12
13
}
13
14
14
15
fn vtable_nop_cast ( ) {
@@ -531,3 +532,32 @@ fn modulo_assoc() {
531
532
532
533
( & ( ) as & dyn Trait as & dyn Middle < ( ) > ) . say_hello ( & 0 ) ;
533
534
}
535
+
536
+ fn bidirectional_subtyping ( ) {
537
+ // Test that transmuting between subtypes of dyn traits is fine, even in the
538
+ // "wrong direction", i.e. going from a lower-ranked to a higher-ranked dyn trait.
539
+ // Note that compared to the `dyn-transmute-inner-binder` test, the `for` is on the
540
+ // *outside* here!
541
+
542
+ trait Trait < U : ?Sized > { }
543
+ impl < T , U : ?Sized > Trait < U > for T { }
544
+
545
+ struct Wrapper < T : ?Sized > ( T ) ;
546
+
547
+ let x: & dyn Trait < fn ( & ' static ( ) ) > = & ( ) ;
548
+ let _y: & dyn for < ' a > Trait < fn ( & ' a ( ) ) > = unsafe { std:: mem:: transmute ( x) } ;
549
+
550
+ let x: & dyn for < ' a > Trait < fn ( & ' a ( ) ) > = & ( ) ;
551
+ let _y: & dyn Trait < fn ( & ' static ( ) ) > = unsafe { std:: mem:: transmute ( x) } ;
552
+
553
+ let x: & dyn Trait < dyn Trait < fn ( & ' static ( ) ) > > = & ( ) ;
554
+ let _y: & dyn for < ' a > Trait < dyn Trait < fn ( & ' a ( ) ) > > = unsafe { std:: mem:: transmute ( x) } ;
555
+
556
+ let x: & dyn for < ' a > Trait < dyn Trait < fn ( & ' a ( ) ) > > = & ( ) ;
557
+ let _y: & dyn Trait < dyn Trait < fn ( & ' static ( ) ) > > = unsafe { std:: mem:: transmute ( x) } ;
558
+
559
+ // This lowers to a ptr-to-ptr cast (which behaves like a transmute)
560
+ // and not an unsizing coercion:
561
+ let x: * const dyn for < ' a > Trait < & ' a ( ) > = & ( ) ;
562
+ let _y: * const Wrapper < dyn Trait < & ' static ( ) > > = x as _ ;
563
+ }
0 commit comments