From d6fe5334185385372d1fe8f1c9df8f5d3e7be788 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 24 Sep 2025 10:28:52 +0200 Subject: add tests --- .../method/broken-deref-chain.current.stderr | 19 +++++++++ tests/ui/impl-trait/method/broken-deref-chain.rs | 47 ++++++++++++++++++++++ .../method/would-constrain-opaque.current.stderr | 29 +++++++++++++ .../method/would-constrain-opaque.next.stderr | 27 +++++++++++++ .../ui/impl-trait/method/would-constrain-opaque.rs | 39 ++++++++++++++++++ 5 files changed, 161 insertions(+) create mode 100644 tests/ui/impl-trait/method/broken-deref-chain.current.stderr create mode 100644 tests/ui/impl-trait/method/broken-deref-chain.rs create mode 100644 tests/ui/impl-trait/method/would-constrain-opaque.current.stderr create mode 100644 tests/ui/impl-trait/method/would-constrain-opaque.next.stderr create mode 100644 tests/ui/impl-trait/method/would-constrain-opaque.rs diff --git a/tests/ui/impl-trait/method/broken-deref-chain.current.stderr b/tests/ui/impl-trait/method/broken-deref-chain.current.stderr new file mode 100644 index 00000000000..726f076b183 --- /dev/null +++ b/tests/ui/impl-trait/method/broken-deref-chain.current.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/broken-deref-chain.rs:41:30 + | +LL | fn trait_method() -> impl Trait { + | ---------- the found opaque type +... +LL | x.trait_method(); + | - here the type of `x` is inferred to be `Foo` +LL | let _: Foo = x; // Test that we did not apply the deref step + | ----------- ^ expected `Foo`, found `Foo` + | | + | expected due to this + | + = note: expected struct `Foo` + found struct `Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/method/broken-deref-chain.rs b/tests/ui/impl-trait/method/broken-deref-chain.rs new file mode 100644 index 00000000000..8b45e044f43 --- /dev/null +++ b/tests/ui/impl-trait/method/broken-deref-chain.rs @@ -0,0 +1,47 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +// An annoying edge case of method selection. While computing the deref-chain +// constrains `T` to `u32`, the final method candidate does not and instead +// constrains to `i32`. In this case, we no longer check that the opaque +// remains unconstrained. Both method calls in this test constrain the opaque +// to `i32`. +use std::ops::Deref; + +struct Foo(T, U); +impl Deref for Foo { + type Target = U; + fn deref(&self) -> &Self::Target { + &self.1 + } +} + +impl Foo { + fn method(&self) {} +} +fn inherent_method() -> impl Sized { + if false { + let x = Foo(Default::default(), inherent_method()); + x.method(); + let _: Foo = x; // Test that we did not apply the deref step + } + 1i32 +} + +trait Trait { + fn trait_method(&self) {} +} +impl Trait for Foo {} +impl Trait for i32 {} +fn trait_method() -> impl Trait { + if false { + let x = Foo(Default::default(), trait_method()); + x.trait_method(); + let _: Foo = x; // Test that we did not apply the deref step + //[current]~^ ERROR mismatched types + } + 1i32 +} + +fn main() {} diff --git a/tests/ui/impl-trait/method/would-constrain-opaque.current.stderr b/tests/ui/impl-trait/method/would-constrain-opaque.current.stderr new file mode 100644 index 00000000000..60533a39c53 --- /dev/null +++ b/tests/ui/impl-trait/method/would-constrain-opaque.current.stderr @@ -0,0 +1,29 @@ +error[E0599]: no method named `method` found for reference `&impl Sized` in the current scope + --> $DIR/would-constrain-opaque.rs:28:11 + | +LL | x.method(); + | ^^^^^^ method not found in `&impl Sized` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Trait` defines an item `method`, perhaps you need to implement it + --> $DIR/would-constrain-opaque.rs:15:1 + | +LL | trait Trait: Sized { + | ^^^^^^^^^^^^^^^^^^ + +error[E0599]: no method named `method` found for reference `&impl Sized` in the current scope + --> $DIR/would-constrain-opaque.rs:30:11 + | +LL | x.method(); + | ^^^^^^ method not found in `&impl Sized` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Trait` defines an item `method`, perhaps you need to implement it + --> $DIR/would-constrain-opaque.rs:15:1 + | +LL | trait Trait: Sized { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/method/would-constrain-opaque.next.stderr b/tests/ui/impl-trait/method/would-constrain-opaque.next.stderr new file mode 100644 index 00000000000..23a4ceb826a --- /dev/null +++ b/tests/ui/impl-trait/method/would-constrain-opaque.next.stderr @@ -0,0 +1,27 @@ +error[E0599]: no method named `method` found for reference `&_` in the current scope + --> $DIR/would-constrain-opaque.rs:28:11 + | +LL | x.method(); + | ^^^^^^ method not found in `&_` + | + = help: items from traits can only be used if the trait is implemented and in scope +help: trait `Trait` which provides `method` is implemented but not in scope; perhaps you want to import it + | +LL + use Trait; + | + +error[E0599]: no method named `method` found for reference `&_` in the current scope + --> $DIR/would-constrain-opaque.rs:30:11 + | +LL | x.method(); + | ^^^^^^ method not found in `&_` + | + = help: items from traits can only be used if the trait is implemented and in scope +help: trait `Trait` which provides `method` is implemented but not in scope; perhaps you want to import it + | +LL + use Trait; + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/method/would-constrain-opaque.rs b/tests/ui/impl-trait/method/would-constrain-opaque.rs new file mode 100644 index 00000000000..8dd32282529 --- /dev/null +++ b/tests/ui/impl-trait/method/would-constrain-opaque.rs @@ -0,0 +1,39 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +// If we don't treat `impl Sized` as rigid, the first call would +// resolve to the trait method, constraining the opaque, while the +// second call would resolve to the inherent method. +// +// We avoid cases like this by rejecting candidates which constrain +// opaque types encountered in the autoderef chain. +// +// FIXME(-Znext-solver): ideally we would note that the inference variable +// is an opaque type in the error message and change this to a type annotations +// needed error. + +trait Trait: Sized { + fn method(self) {} +} +impl Trait for &Foo {} + +struct Foo; +impl Foo { + fn method(&self) {} +} + +fn define_opaque(b: bool) -> impl Sized { + if b { + let x = &define_opaque(false); + x.method(); + //~^ ERROR no method named `method` found for reference + x.method(); + //~^ ERROR no method named `method` found for reference + } + + Foo +} + +fn main() { + define_opaque(true); +} -- cgit 1.4.1-3-g733a5