Skip to content

Commit 508b75d

Browse files
committed
add tests
1 parent 46d5ac7 commit 508b75d

File tree

5 files changed

+161
-0
lines changed

5 files changed

+161
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/broken-deref-chain.rs:41:30
3+
|
4+
LL | fn trait_method() -> impl Trait {
5+
| ---------- the found opaque type
6+
...
7+
LL | x.trait_method();
8+
| - here the type of `x` is inferred to be `Foo<u32, impl Trait>`
9+
LL | let _: Foo<i32, _> = x; // Test that we did not apply the deref step
10+
| ----------- ^ expected `Foo<i32, _>`, found `Foo<u32, impl Trait>`
11+
| |
12+
| expected due to this
13+
|
14+
= note: expected struct `Foo<i32, _>`
15+
found struct `Foo<u32, impl Trait>`
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//@ revisions: current next
2+
//@[next] compile-flags: -Znext-solver
3+
//@[next] check-pass
4+
5+
// An annoying edge case of method selection. While computing the deref-chain
6+
// constrains `T` to `u32`, the final method candidate does not and instead
7+
// constrains to `i32`. In this case, we no longer check that the opaque
8+
// remains unconstrained. Both method calls in this test constrain the opaque
9+
// to `i32`.
10+
use std::ops::Deref;
11+
12+
struct Foo<T, U>(T, U);
13+
impl<U> Deref for Foo<u32, U> {
14+
type Target = U;
15+
fn deref(&self) -> &Self::Target {
16+
&self.1
17+
}
18+
}
19+
20+
impl Foo<i32, i32> {
21+
fn method(&self) {}
22+
}
23+
fn inherent_method() -> impl Sized {
24+
if false {
25+
let x = Foo(Default::default(), inherent_method());
26+
x.method();
27+
let _: Foo<i32, _> = x; // Test that we did not apply the deref step
28+
}
29+
1i32
30+
}
31+
32+
trait Trait {
33+
fn trait_method(&self) {}
34+
}
35+
impl Trait for Foo<i32, i32> {}
36+
impl Trait for i32 {}
37+
fn trait_method() -> impl Trait {
38+
if false {
39+
let x = Foo(Default::default(), trait_method());
40+
x.trait_method();
41+
let _: Foo<i32, _> = x; // Test that we did not apply the deref step
42+
//[current]~^ ERROR mismatched types
43+
}
44+
1i32
45+
}
46+
47+
fn main() {}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error[E0599]: no method named `method` found for reference `&impl Sized` in the current scope
2+
--> $DIR/would-constrain-opaque.rs:28:11
3+
|
4+
LL | x.method();
5+
| ^^^^^^ method not found in `&impl Sized`
6+
|
7+
= help: items from traits can only be used if the trait is implemented and in scope
8+
note: `Trait` defines an item `method`, perhaps you need to implement it
9+
--> $DIR/would-constrain-opaque.rs:15:1
10+
|
11+
LL | trait Trait: Sized {
12+
| ^^^^^^^^^^^^^^^^^^
13+
14+
error[E0599]: no method named `method` found for reference `&impl Sized` in the current scope
15+
--> $DIR/would-constrain-opaque.rs:30:11
16+
|
17+
LL | x.method();
18+
| ^^^^^^ method not found in `&impl Sized`
19+
|
20+
= help: items from traits can only be used if the trait is implemented and in scope
21+
note: `Trait` defines an item `method`, perhaps you need to implement it
22+
--> $DIR/would-constrain-opaque.rs:15:1
23+
|
24+
LL | trait Trait: Sized {
25+
| ^^^^^^^^^^^^^^^^^^
26+
27+
error: aborting due to 2 previous errors
28+
29+
For more information about this error, try `rustc --explain E0599`.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0599]: no method named `method` found for reference `&_` in the current scope
2+
--> $DIR/would-constrain-opaque.rs:28:11
3+
|
4+
LL | x.method();
5+
| ^^^^^^ method not found in `&_`
6+
|
7+
= help: items from traits can only be used if the trait is implemented and in scope
8+
help: trait `Trait` which provides `method` is implemented but not in scope; perhaps you want to import it
9+
|
10+
LL + use Trait;
11+
|
12+
13+
error[E0599]: no method named `method` found for reference `&_` in the current scope
14+
--> $DIR/would-constrain-opaque.rs:30:11
15+
|
16+
LL | x.method();
17+
| ^^^^^^ method not found in `&_`
18+
|
19+
= help: items from traits can only be used if the trait is implemented and in scope
20+
help: trait `Trait` which provides `method` is implemented but not in scope; perhaps you want to import it
21+
|
22+
LL + use Trait;
23+
|
24+
25+
error: aborting due to 2 previous errors
26+
27+
For more information about this error, try `rustc --explain E0599`.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//@ revisions: current next
2+
//@[next] compile-flags: -Znext-solver
3+
4+
// If we don't treat `impl Sized` as rigid, the first call would
5+
// resolve to the trait method, constraining the opaque, while the
6+
// second call would resolve to the inherent method.
7+
//
8+
// We avoid cases like this by rejecting candidates which constrain
9+
// opaque types encountered in the autoderef chain.
10+
//
11+
// FIXME(-Znext-solver): ideally we would note that the inference variable
12+
// is an opaque type in the error message and change this to a type annotations
13+
// needed error.
14+
15+
trait Trait: Sized {
16+
fn method(self) {}
17+
}
18+
impl Trait for &Foo {}
19+
20+
struct Foo;
21+
impl Foo {
22+
fn method(&self) {}
23+
}
24+
25+
fn define_opaque(b: bool) -> impl Sized {
26+
if b {
27+
let x = &define_opaque(false);
28+
x.method();
29+
//~^ ERROR no method named `method` found for reference
30+
x.method();
31+
//~^ ERROR no method named `method` found for reference
32+
}
33+
34+
Foo
35+
}
36+
37+
fn main() {
38+
define_opaque(true);
39+
}

0 commit comments

Comments
 (0)