summaryrefslogtreecommitdiffstats
path: root/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs
blob: 9e53ff07917287492d3f9625d8250ac684e2130b (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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize)]
#![feature(unsized_locals, unsized_fn_params)]
//~^ WARN the feature `unsized_locals` is incomplete

// This tests a few edge-cases around `arbitrary_self_types`. Most specifically,
// it checks that the `ObjectCandidate` you get from method matching can't
// match a trait with the same DefId as a supertrait but a bad type parameter.

use std::marker::PhantomData;

mod internal {
    use std::ops::{CoerceUnsized, Deref, DispatchFromDyn};
    use std::marker::{PhantomData, Unsize};

    pub struct Smaht<T: ?Sized, MISC>(pub Box<T>, pub PhantomData<MISC>);

    impl<T: ?Sized, MISC> Deref for Smaht<T, MISC> {
        type Target = T;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    impl<T: ?Sized + Unsize<U>, U: ?Sized, MISC> CoerceUnsized<Smaht<U, MISC>>
        for Smaht<T, MISC>
    {}
    impl<T: ?Sized + Unsize<U>, U: ?Sized, MISC> DispatchFromDyn<Smaht<U, MISC>>
        for Smaht<T, MISC>
    {}

    pub trait Foo: X<u32> {}
    pub trait X<T> {
        fn foo(self: Smaht<Self, T>) -> T;
    }

    impl X<u32> for () {
        fn foo(self: Smaht<Self, u32>) -> u32 {
            0
        }
    }

    pub trait Marker {}
    impl Marker for dyn Foo {}
    impl<T: Marker + ?Sized> X<u64> for T {
        fn foo(self: Smaht<Self, u64>) -> u64 {
            1
        }
    }

    impl Deref for dyn Foo {
        type Target = ();
        fn deref(&self) -> &() { &() }
    }

    impl Foo for () {}
}

pub trait FinalFoo {
    fn foo(&self) -> u8;
}

impl FinalFoo for () {
    fn foo(&self) -> u8 { 0 }
}

mod nuisance_foo {
    pub trait NuisanceFoo {
        fn foo(self);
    }

    impl<T: ?Sized> NuisanceFoo for T {
        fn foo(self) {}
    }
}


fn objectcandidate_impl() {
    let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData);
    let x: internal::Smaht<dyn internal::Foo, u32> = x;

    // This picks `<dyn internal::Foo as X<u32>>::foo` via `ObjectCandidate`.
    //
    // The `TraitCandidate` is not relevant because `X` is not in scope.
    let z = x.foo();

    // Observe the type of `z` is `u32`
    let _seetype: () = z; //~ ERROR mismatched types
    //~| expected `()`, found `u32`
}

fn traitcandidate_impl() {
    use internal::X;

    let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData);
    let x: internal::Smaht<dyn internal::Foo, u64> = x;

    // This picks `<dyn internal::Foo as X<u64>>::foo` via `TraitCandidate`.
    //
    // The `ObjectCandidate` does not apply, as it only applies to
    // `X<u32>` (and not `X<u64>`).
    let z = x.foo();

    // Observe the type of `z` is `u64`
    let _seetype: () = z; //~ ERROR mismatched types
    //~| expected `()`, found `u64`
}

fn traitcandidate_impl_with_nuisance() {
    use internal::X;
    use nuisance_foo::NuisanceFoo;

    let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData);
    let x: internal::Smaht<dyn internal::Foo, u64> = x;

    // This picks `<dyn internal::Foo as X<u64>>::foo` via `TraitCandidate`.
    //
    // The `ObjectCandidate` does not apply, as it only applies to
    // `X<u32>` (and not `X<u64>`).
    //
    // The NuisanceFoo impl has the same priority as the `X` impl,
    // so we get a conflict.
    let z = x.foo(); //~ ERROR multiple applicable items in scope
}


fn neither_impl() {
    let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData);
    let x: internal::Smaht<dyn internal::Foo, u64> = x;

    // This can't pick the `TraitCandidate` impl, because `Foo` is not
    // imported. However, this also can't pick the `ObjectCandidate`
    // impl, because it only applies to `X<u32>` (and not `X<u64>`).
    //
    // Therefore, neither of the candidates is applicable, and we pick
    // the `FinalFoo` impl after another deref, which will return `u8`.
    let z = x.foo();

    // Observe the type of `z` is `u8`
    let _seetype: () = z; //~ ERROR mismatched types
    //~| expected `()`, found `u8`
}

fn both_impls() {
    use internal::X;

    let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData);
    let x: internal::Smaht<dyn internal::Foo, u32> = x;

    // This can pick both the `TraitCandidate` and the `ObjectCandidate` impl.
    //
    // However, the `ObjectCandidate` is considered an "inherent candidate",
    // and therefore has priority over both the `TraitCandidate` as well as
    // any other "nuisance" candidate" (if present).
    let z = x.foo();

    // Observe the type of `z` is `u32`
    let _seetype: () = z; //~ ERROR mismatched types
    //~| expected `()`, found `u32`
}


fn both_impls_with_nuisance() {
    // Similar to the `both_impls` example, except with a nuisance impl to
    // make sure the `ObjectCandidate` indeed has a higher priority.

    use internal::X;
    use nuisance_foo::NuisanceFoo;

    let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData);
    let x: internal::Smaht<dyn internal::Foo, u32> = x;
    let z = x.foo();

    // Observe the type of `z` is `u32`
    let _seetype: () = z; //~ ERROR mismatched types
    //~| expected `()`, found `u32`
}

fn main() {
}