Skip to content

Commit 0ceb30d

Browse files
committed
add tests to a few edge cases in method lookup
These aren't fixed by this PR, but were broken in a few older attempts at it. Make sure they don't regress.
1 parent 8d26c75 commit 0ceb30d

File tree

3 files changed

+290
-0
lines changed

3 files changed

+290
-0
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize, unsized_locals)]
2+
3+
// This tests a few edge-cases around `arbitrary_self_types`. Most specifically,
4+
// it checks that the `ObjectCandidate` you get from method matching can't
5+
// match a trait with the same DefId as a supertrait but a bad type parameter.
6+
7+
use std::marker::PhantomData;
8+
9+
mod internal {
10+
use std::ops::{CoerceUnsized, Deref, DispatchFromDyn};
11+
use std::marker::{PhantomData, Unsize};
12+
13+
pub struct Smaht<T: ?Sized, MISC>(pub Box<T>, pub PhantomData<MISC>);
14+
15+
impl<T: ?Sized, MISC> Deref for Smaht<T, MISC> {
16+
type Target = T;
17+
18+
fn deref(&self) -> &Self::Target {
19+
&self.0
20+
}
21+
}
22+
impl<T: ?Sized + Unsize<U>, U: ?Sized, MISC> CoerceUnsized<Smaht<U, MISC>>
23+
for Smaht<T, MISC>
24+
{}
25+
impl<T: ?Sized + Unsize<U>, U: ?Sized, MISC> DispatchFromDyn<Smaht<U, MISC>>
26+
for Smaht<T, MISC>
27+
{}
28+
29+
pub trait Foo: X<u32> {}
30+
pub trait X<T> {
31+
fn foo(self: Smaht<Self, T>) -> T;
32+
}
33+
34+
impl X<u32> for () {
35+
fn foo(self: Smaht<Self, u32>) -> u32 {
36+
0
37+
}
38+
}
39+
40+
pub trait Marker {}
41+
impl Marker for dyn Foo {}
42+
impl<T: Marker + ?Sized> X<u64> for T {
43+
fn foo(self: Smaht<Self, u64>) -> u64 {
44+
1
45+
}
46+
}
47+
48+
impl Deref for dyn Foo {
49+
type Target = ();
50+
fn deref(&self) -> &() { &() }
51+
}
52+
53+
impl Foo for () {}
54+
}
55+
56+
pub trait FinalFoo {
57+
fn foo(&self) -> u8;
58+
}
59+
60+
impl FinalFoo for () {
61+
fn foo(&self) -> u8 { 0 }
62+
}
63+
64+
mod nuisance_foo {
65+
pub trait NuisanceFoo {
66+
fn foo(self);
67+
}
68+
69+
impl<T: ?Sized> NuisanceFoo for T {
70+
fn foo(self) {}
71+
}
72+
}
73+
74+
75+
fn objectcandidate_impl() {
76+
let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData);
77+
let x: internal::Smaht<dyn internal::Foo, u32> = x;
78+
79+
// This picks `<dyn internal::Foo as X<u32>>::foo` via `ObjectCandidate`.
80+
//
81+
// The `TraitCandidate` is not relevant because `X` is not in scope.
82+
let z = x.foo();
83+
84+
// Observe the type of `z` is `u32`
85+
let _seetype: () = z; //~ ERROR mismatched types
86+
//~| expected (), found u32
87+
}
88+
89+
fn traitcandidate_impl() {
90+
use internal::X;
91+
92+
let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData);
93+
let x: internal::Smaht<dyn internal::Foo, u64> = x;
94+
95+
// This picks `<dyn internal::Foo as X<u64>>::foo` via `TraitCandidate`.
96+
//
97+
// The `ObjectCandidate` does not apply, as it only applies to
98+
// `X<u32>` (and not `X<u64>`).
99+
let z = x.foo();
100+
101+
// Observe the type of `z` is `u64`
102+
let _seetype: () = z; //~ ERROR mismatched types
103+
//~| expected (), found u64
104+
}
105+
106+
fn traitcandidate_impl_with_nuisance() {
107+
use internal::X;
108+
use nuisance_foo::NuisanceFoo;
109+
110+
let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData);
111+
let x: internal::Smaht<dyn internal::Foo, u64> = x;
112+
113+
// This picks `<dyn internal::Foo as X<u64>>::foo` via `TraitCandidate`.
114+
//
115+
// The `ObjectCandidate` does not apply, as it only applies to
116+
// `X<u32>` (and not `X<u64>`).
117+
//
118+
// The NuisanceFoo impl has the same priority as the `X` impl,
119+
// so we get a conflict.
120+
let z = x.foo(); //~ ERROR multiple applicable items in scope
121+
}
122+
123+
124+
fn neither_impl() {
125+
let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData);
126+
let x: internal::Smaht<dyn internal::Foo, u64> = x;
127+
128+
// This can't pick the `TraitCandidate` impl, because `Foo` is not
129+
// imported. However, this also can't pick the `ObjectCandidate`
130+
// impl, because it only applies to `X<u32>` (and not `X<u64>`).
131+
//
132+
// Therefore, neither of the candidates is applicable, and we pick
133+
// the `FinalFoo` impl after another deref, which will return `u8`.
134+
let z = x.foo();
135+
136+
// Observe the type of `z` is `u8`
137+
let _seetype: () = z; //~ ERROR mismatched types
138+
//~| expected (), found u8
139+
}
140+
141+
fn both_impls() {
142+
use internal::X;
143+
144+
let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData);
145+
let x: internal::Smaht<dyn internal::Foo, u32> = x;
146+
147+
// This can pick both the `TraitCandidate` and the `ObjectCandidate` impl.
148+
//
149+
// However, the `ObjectCandidate` is considered an "inherent candidate",
150+
// and therefore has priority over both the `TraitCandidate` as well as
151+
// any other "nuisance" candidate" (if present).
152+
let z = x.foo();
153+
154+
// Observe the type of `z` is `u32`
155+
let _seetype: () = z; //~ ERROR mismatched types
156+
//~| expected (), found u32
157+
}
158+
159+
160+
fn both_impls_with_nuisance() {
161+
// Similar to the `both_impls` example, except with a nuisance impl to
162+
// make sure the `ObjectCandidate` indeed has a higher priority.
163+
164+
use internal::X;
165+
use nuisance_foo::NuisanceFoo;
166+
167+
let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData);
168+
let x: internal::Smaht<dyn internal::Foo, u32> = x;
169+
let z = x.foo();
170+
171+
// Observe the type of `z` is `u32`
172+
let _seetype: () = z; //~ ERROR mismatched types
173+
//~| expected (), found u32
174+
}
175+
176+
fn main() {
177+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:85:24
3+
|
4+
LL | let _seetype: () = z; //~ ERROR mismatched types
5+
| ^ expected (), found u32
6+
|
7+
= note: expected type `()`
8+
found type `u32`
9+
10+
error[E0308]: mismatched types
11+
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:102:24
12+
|
13+
LL | let _seetype: () = z; //~ ERROR mismatched types
14+
| ^ expected (), found u64
15+
|
16+
= note: expected type `()`
17+
found type `u64`
18+
19+
error[E0034]: multiple applicable items in scope
20+
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:120:15
21+
|
22+
LL | let z = x.foo(); //~ ERROR multiple applicable items in scope
23+
| ^^^ multiple `foo` found
24+
|
25+
note: candidate #1 is defined in an impl of the trait `internal::X` for the type `_`
26+
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:43:9
27+
|
28+
LL | fn foo(self: Smaht<Self, u64>) -> u64 {
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
note: candidate #2 is defined in an impl of the trait `nuisance_foo::NuisanceFoo` for the type `_`
31+
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9
32+
|
33+
LL | fn foo(self) {}
34+
| ^^^^^^^^^^^^
35+
note: candidate #3 is defined in the trait `FinalFoo`
36+
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:57:5
37+
|
38+
LL | fn foo(&self) -> u8;
39+
| ^^^^^^^^^^^^^^^^^^^^
40+
= help: to disambiguate the method call, write `FinalFoo::foo(x)` instead
41+
42+
error[E0308]: mismatched types
43+
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:137:24
44+
|
45+
LL | let _seetype: () = z; //~ ERROR mismatched types
46+
| ^ expected (), found u8
47+
|
48+
= note: expected type `()`
49+
found type `u8`
50+
51+
error[E0308]: mismatched types
52+
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:155:24
53+
|
54+
LL | let _seetype: () = z; //~ ERROR mismatched types
55+
| ^ expected (), found u32
56+
|
57+
= note: expected type `()`
58+
found type `u32`
59+
60+
error[E0308]: mismatched types
61+
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:172:24
62+
|
63+
LL | let _seetype: () = z; //~ ERROR mismatched types
64+
| ^ expected (), found u32
65+
|
66+
= note: expected type `()`
67+
found type `u32`
68+
69+
error: aborting due to 6 previous errors
70+
71+
Some errors occurred: E0034, E0308.
72+
For more information about an error, try `rustc --explain E0034`.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// compile-pass
2+
3+
// Check that method probing ObjectCandidate works in the presence of
4+
// auto traits and/or HRTBs.
5+
6+
mod internal {
7+
pub trait MyObject<'a> {
8+
type Output;
9+
10+
fn foo(&self) -> Self::Output;
11+
}
12+
13+
impl<'a> MyObject<'a> for () {
14+
type Output = &'a u32;
15+
16+
fn foo(&self) -> Self::Output { &4 }
17+
}
18+
}
19+
20+
fn t1(d: &dyn for<'a> internal::MyObject<'a, Output=&'a u32>) {
21+
d.foo();
22+
}
23+
24+
fn t2(d: &dyn internal::MyObject<'static, Output=&'static u32>) {
25+
d.foo();
26+
}
27+
28+
fn t3(d: &(dyn for<'a> internal::MyObject<'a, Output=&'a u32> + Sync)) {
29+
d.foo();
30+
}
31+
32+
fn t4(d: &(dyn internal::MyObject<'static, Output=&'static u32> + Sync)) {
33+
d.foo();
34+
}
35+
36+
fn main() {
37+
t1(&());
38+
t2(&());
39+
t3(&());
40+
t4(&());
41+
}

0 commit comments

Comments
 (0)