|
| 1 | +// Targeted tests for the higher-ranked subtyping code. |
| 2 | + |
| 3 | +#![allow(dead_code)] |
| 4 | + |
| 5 | +// revisions: bound_a_vs_bound_a |
| 6 | +// revisions: bound_a_vs_bound_b |
| 7 | +// revisions: bound_inv_a_vs_bound_inv_b |
| 8 | +// revisions: bound_co_a_vs_bound_co_b |
| 9 | +// revisions: bound_a_vs_free_x |
| 10 | +// revisions: free_x_vs_free_x |
| 11 | +// revisions: free_x_vs_free_y |
| 12 | +// revisions: free_inv_x_vs_free_inv_y |
| 13 | +// revisions: bound_a_b_vs_bound_a |
| 14 | +// revisions: bound_co_a_b_vs_bound_co_a |
| 15 | +// revisions: bound_contra_a_contra_b_ret_co_a |
| 16 | +// revisions: bound_co_a_co_b_ret_contra_a |
| 17 | +// revisions: bound_inv_a_b_vs_bound_inv_a |
| 18 | +// revisions: bound_a_b_ret_a_vs_bound_a_ret_a |
| 19 | + |
| 20 | +//[bound_a_vs_bound_a] check-pass |
| 21 | +//[bound_a_vs_bound_b] check-pass |
| 22 | +//[bound_inv_a_vs_bound_inv_b] check-pass |
| 23 | +//[bound_co_a_vs_bound_co_b] check-pass |
| 24 | +//[free_x_vs_free_x] check-pass |
| 25 | +//[bound_co_a_b_vs_bound_co_a] check-pass |
| 26 | +//[bound_co_a_co_b_ret_contra_a] check-pass |
| 27 | +//[bound_a_b_vs_bound_a] check-pass |
| 28 | +//[bound_contra_a_contra_b_ret_co_a] check-pass |
| 29 | + |
| 30 | +// compile-flags: -Z borrowck=mir |
| 31 | +// ignore-compare-mode-nll |
| 32 | +// FIXME(nll): When stabilizing, this test should be replace with `hr-subtype.rs` |
| 33 | +// The two would normally be just revisions, but this test uses revisions heavily, so splitting into |
| 34 | +// a separate test is just easier. |
| 35 | + |
| 36 | +fn gimme<T>(_: Option<T>) {} |
| 37 | + |
| 38 | +struct Inv<'a> { |
| 39 | + x: *mut &'a u32, |
| 40 | +} |
| 41 | + |
| 42 | +struct Co<'a> { |
| 43 | + x: fn(&'a u32), |
| 44 | +} |
| 45 | + |
| 46 | +struct Contra<'a> { |
| 47 | + x: &'a u32, |
| 48 | +} |
| 49 | + |
| 50 | +macro_rules! check { |
| 51 | + ($rev:ident: ($t1:ty, $t2:ty)) => { |
| 52 | + #[cfg($rev)] |
| 53 | + fn subtype<'x, 'y: 'x, 'z: 'y>() { |
| 54 | + gimme::<$t2>(None::<$t1>); |
| 55 | + //[free_inv_x_vs_free_inv_y]~^ ERROR |
| 56 | + } |
| 57 | + |
| 58 | + #[cfg($rev)] |
| 59 | + fn supertype<'x, 'y: 'x, 'z: 'y>() { |
| 60 | + gimme::<$t1>(None::<$t2>); |
| 61 | + //[bound_a_vs_free_x]~^ ERROR |
| 62 | + //[free_x_vs_free_y]~^^ ERROR |
| 63 | + //[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR |
| 64 | + //[bound_inv_a_b_vs_bound_inv_a]~| ERROR |
| 65 | + //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^^ ERROR |
| 66 | + //[free_inv_x_vs_free_inv_y]~^^^^^^ ERROR |
| 67 | + } |
| 68 | + }; |
| 69 | +} |
| 70 | + |
| 71 | +// If both have bound regions, they are equivalent, regardless of |
| 72 | +// variant. |
| 73 | +check! { bound_a_vs_bound_a: (for<'a> fn(&'a u32), |
| 74 | +for<'a> fn(&'a u32)) } |
| 75 | +check! { bound_a_vs_bound_b: (for<'a> fn(&'a u32), |
| 76 | +for<'b> fn(&'b u32)) } |
| 77 | +check! { bound_inv_a_vs_bound_inv_b: (for<'a> fn(Inv<'a>), |
| 78 | +for<'b> fn(Inv<'b>)) } |
| 79 | +check! { bound_co_a_vs_bound_co_b: (for<'a> fn(Co<'a>), |
| 80 | +for<'b> fn(Co<'b>)) } |
| 81 | + |
| 82 | +// Bound is a subtype of free. |
| 83 | +check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), |
| 84 | +fn(&'x u32)) } |
| 85 | + |
| 86 | +// Two free regions are relatable if subtyping holds. |
| 87 | +check! { free_x_vs_free_x: (fn(&'x u32), |
| 88 | +fn(&'x u32)) } |
| 89 | +check! { free_x_vs_free_y: (fn(&'x u32), |
| 90 | +fn(&'y u32)) } |
| 91 | +check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), |
| 92 | +fn(Inv<'y>)) } |
| 93 | + |
| 94 | +// Somewhat surprisingly, a fn taking two distinct bound lifetimes and |
| 95 | +// a fn taking one bound lifetime can be interchangeable, but only if |
| 96 | +// we are co- or contra-variant with respect to both lifetimes. |
| 97 | +// |
| 98 | +// The reason is: |
| 99 | +// - if we are covariant, then 'a and 'b can be set to the call-site |
| 100 | +// intersection; |
| 101 | +// - if we are contravariant, then 'a can be inferred to 'static. |
| 102 | +check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32), |
| 103 | +for<'a> fn(&'a u32, &'a u32)) } |
| 104 | +check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>), |
| 105 | +for<'a> fn(Co<'a>, Co<'a>)) } |
| 106 | +check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>, |
| 107 | +for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>) } |
| 108 | +check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>, |
| 109 | +for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) } |
| 110 | + |
| 111 | +// If we make those lifetimes invariant, then the two types are not interchangeable. |
| 112 | +check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), |
| 113 | +for<'a> fn(Inv<'a>, Inv<'a>)) } |
| 114 | +check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32, |
| 115 | +for<'a> fn(&'a u32, &'a u32) -> &'a u32) } |
| 116 | + |
| 117 | +fn main() {} |
0 commit comments