summaryrefslogtreecommitdiffstats
path: root/tests/ui/hr-subtype/hr-subtype.rs
blob: c770e0de85c0805b80b26a8c380da651db35e786 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Targeted tests for the higher-ranked subtyping code.

#![allow(dead_code)]

// revisions: bound_a_vs_bound_a
// revisions: bound_a_vs_bound_b
// revisions: bound_inv_a_vs_bound_inv_b
// revisions: bound_co_a_vs_bound_co_b
// revisions: bound_a_vs_free_x
// revisions: free_x_vs_free_x
// revisions: free_x_vs_free_y
// revisions: free_inv_x_vs_free_inv_y
// revisions: bound_a_b_vs_bound_a
// revisions: bound_co_a_b_vs_bound_co_a
// revisions: bound_contra_a_contra_b_ret_co_a
// revisions: bound_co_a_co_b_ret_contra_a
// revisions: bound_inv_a_b_vs_bound_inv_a
// revisions: bound_a_b_ret_a_vs_bound_a_ret_a

//[bound_a_vs_bound_a] check-pass
//[bound_a_vs_bound_b] check-pass
//[bound_inv_a_vs_bound_inv_b] check-pass
//[bound_co_a_vs_bound_co_b] check-pass
//[free_x_vs_free_x] check-pass
//[bound_co_a_b_vs_bound_co_a] check-pass
//[bound_co_a_co_b_ret_contra_a] check-pass
//[bound_a_b_vs_bound_a] check-pass
//[bound_contra_a_contra_b_ret_co_a] check-pass

fn gimme<T>(_: Option<T>) {}

struct Inv<'a> {
    x: *mut &'a u32,
}

struct Co<'a> {
    x: fn(&'a u32),
}

struct Contra<'a> {
    x: &'a u32,
}

macro_rules! check {
    ($rev:ident: ($t1:ty, $t2:ty)) => {
        #[cfg($rev)]
        fn subtype<'x, 'y: 'x, 'z: 'y>() {
            gimme::<$t2>(None::<$t1>);
            //[free_inv_x_vs_free_inv_y]~^ ERROR
        }

        #[cfg($rev)]
        fn supertype<'x, 'y: 'x, 'z: 'y>() {
            gimme::<$t1>(None::<$t2>);
            //[bound_a_vs_free_x]~^ ERROR
            //[free_x_vs_free_y]~^^ ERROR
            //[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR
            //[bound_inv_a_b_vs_bound_inv_a]~| ERROR
            //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^^ ERROR
            //[free_inv_x_vs_free_inv_y]~^^^^^^ ERROR
        }
    };
}

// If both have bound regions, they are equivalent, regardless of
// variant.
check! { bound_a_vs_bound_a: (for<'a> fn(&'a u32),
for<'a> fn(&'a u32)) }
check! { bound_a_vs_bound_b: (for<'a> fn(&'a u32),
for<'b> fn(&'b u32)) }
check! { bound_inv_a_vs_bound_inv_b: (for<'a> fn(Inv<'a>),
for<'b> fn(Inv<'b>)) }
check! { bound_co_a_vs_bound_co_b: (for<'a> fn(Co<'a>),
for<'b> fn(Co<'b>)) }

// Bound is a subtype of free.
check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
fn(&'x u32)) }

// Two free regions are relatable if subtyping holds.
check! { free_x_vs_free_x: (fn(&'x u32),
fn(&'x u32)) }
check! { free_x_vs_free_y: (fn(&'x u32),
fn(&'y u32)) }
check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
fn(Inv<'y>)) }

// Somewhat surprisingly, a fn taking two distinct bound lifetimes and
// a fn taking one bound lifetime can be interchangeable, but only if
// we are co- or contra-variant with respect to both lifetimes.
//
// The reason is:
// - if we are covariant, then 'a and 'b can be set to the call-site
//   intersection;
// - if we are contravariant, then 'a can be inferred to 'static.
check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
for<'a>    fn(&'a u32, &'a u32)) }
check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
for<'a>    fn(Co<'a>, Co<'a>)) }
check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }

// If we make those lifetimes invariant, then the two types are not interchangeable.
check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
for<'a>    fn(Inv<'a>, Inv<'a>)) }
check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }

fn main() {}