Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change method resolution to constrain hidden types instead of rejecting method candidates #123962

Merged
merged 3 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add some tests
  • Loading branch information
oli-obk committed Jun 13, 2024
commit c75f7283bf52c6e2ec6a178f2b7717a4daddacf4
17 changes: 17 additions & 0 deletions tests/ui/impl-trait/call_method_ambiguous.next.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0282]: type annotations needed
--> $DIR/call_method_ambiguous.rs:29:13
|
LL | let mut iter = foo(n - 1, m);
| ^^^^^^^^
LL |
LL | assert_eq!(iter.get(), 1);
| ---- type must be known at this point
|
help: consider giving `iter` an explicit type
|
LL | let mut iter: /* Type */ = foo(n - 1, m);
| ++++++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0282`.
39 changes: 39 additions & 0 deletions tests/ui/impl-trait/call_method_ambiguous.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@[current] run-pass

#![feature(precise_capturing)]
#![allow(incomplete_features)]

trait Get {
fn get(&mut self) -> u32;
}

impl Get for () {
fn get(&mut self) -> u32 {
0
}
}

impl<T> Get for &mut T
where
T: Get,
{
fn get(&mut self) -> u32 {
T::get(self) + 1
}
}

fn foo(n: usize, m: &mut ()) -> impl use<'_> Get {
if n > 0 {
let mut iter = foo(n - 1, m);
//[next]~^ type annotations needed
assert_eq!(iter.get(), 1);
}
m
}

fn main() {
let g = foo(1, &mut ()).get();
assert_eq!(g, 1);
}
17 changes: 17 additions & 0 deletions tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0282]: type annotations needed
--> $DIR/call_method_on_inherent_impl.rs:18:13
|
LL | let x = my_foo();
| ^
LL |
LL | x.my_debug();
| - type must be known at this point
|
help: consider giving `x` an explicit type
|
LL | let x: /* Type */ = my_foo();
| ++++++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0282`.
25 changes: 25 additions & 0 deletions tests/ui/impl-trait/call_method_on_inherent_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@[current] check-pass

trait MyDebug {
fn my_debug(&self);
}

impl<T> MyDebug for T
where
T: std::fmt::Debug,
{
fn my_debug(&self) {}
}

fn my_foo() -> impl std::fmt::Debug {
if false {
let x = my_foo();
//[next]~^ type annotations needed
x.my_debug();
}
()
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error[E0599]: no method named `my_debug` found for reference `&impl Debug` in the current scope
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:16:11
|
LL | x.my_debug();
| ^^^^^^^^ method not found in `&impl Debug`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:4:1
|
LL | trait MyDebug {
| ^^^^^^^^^^^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0599`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0282]: type annotations needed for `&_`
--> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:14:13
|
LL | let x = &my_foo();
| ^
LL |
LL | x.my_debug();
| -------- type must be known at this point
|
help: consider giving `x` an explicit type, where the placeholders `_` are specified
|
LL | let x: &_ = &my_foo();
| ++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0282`.
22 changes: 22 additions & 0 deletions tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver

trait MyDebug {
fn my_debug(&self);
}

impl MyDebug for &() {
fn my_debug(&self) {}
}

fn my_foo() -> impl std::fmt::Debug {
if false {
let x = &my_foo();
//[next]~^ ERROR: type annotations needed
x.my_debug();
//[current]~^ ERROR: no method named `my_debug`
}
()
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
error[E0599]: no method named `my_debug` found for opaque type `impl Debug` in the current scope
--> $DIR/call_method_on_inherent_impl_ref.rs:20:11
|
LL | fn my_debug(&self);
| -------- the method is available for `&impl Debug` here
...
LL | x.my_debug();
| ^^^^^^^^ method not found in `impl Debug`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it
--> $DIR/call_method_on_inherent_impl_ref.rs:4:1
|
LL | trait MyDebug {
| ^^^^^^^^^^^^^

error[E0391]: cycle detected when computing type of opaque `my_foo::{opaque#0}`
--> $DIR/call_method_on_inherent_impl_ref.rs:15:16
|
LL | fn my_foo() -> impl std::fmt::Debug {
| ^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires type-checking `my_foo`...
--> $DIR/call_method_on_inherent_impl_ref.rs:20:9
|
LL | x.my_debug();
| ^
= note: ...which requires evaluating trait selection obligation `my_foo::{opaque#0}: core::marker::Unpin`...
= note: ...which again requires computing type of opaque `my_foo::{opaque#0}`, completing the cycle
note: cycle used when computing type of `my_foo::{opaque#0}`
--> $DIR/call_method_on_inherent_impl_ref.rs:15:16
|
LL | fn my_foo() -> impl std::fmt::Debug {
| ^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0391, E0599.
For more information about an error, try `rustc --explain E0391`.
31 changes: 31 additions & 0 deletions tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
error[E0282]: type annotations needed
--> $DIR/call_method_on_inherent_impl_ref.rs:18:13
|
LL | let x = my_foo();
| ^
LL |
LL | x.my_debug();
| - type must be known at this point
|
help: consider giving `x` an explicit type
|
LL | let x: /* Type */ = my_foo();
| ++++++++++++

error[E0282]: type annotations needed for `&_`
--> $DIR/call_method_on_inherent_impl_ref.rs:28:13
|
LL | let x = &my_bar();
| ^
LL |
LL | x.my_debug();
| -------- type must be known at this point
|
help: consider giving `x` an explicit type, where the placeholders `_` are specified
|
LL | let x: &_ = &my_bar();
| ++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0282`.
35 changes: 35 additions & 0 deletions tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver

trait MyDebug {
fn my_debug(&self);
}

impl<T> MyDebug for &T
where
T: std::fmt::Debug,
{
fn my_debug(&self) {}
}

fn my_foo() -> impl std::fmt::Debug {
//[current]~^ cycle
if false {
let x = my_foo();
//[next]~^ type annotations needed
x.my_debug();
//[current]~^ no method named `my_debug` found
}
()
}

fn my_bar() -> impl std::fmt::Debug {
if false {
let x = &my_bar();
//[next]~^ type annotations needed
x.my_debug();
}
()
}

fn main() {}
37 changes: 37 additions & 0 deletions tests/ui/impl-trait/call_method_without_import.no_import.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
error[E0599]: no method named `fmt` found for opaque type `impl Debug` in the current scope
--> $DIR/call_method_without_import.rs:17:11
|
LL | x.fmt(f);
| ^^^ method not found in `impl Debug`
--> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
|
= note: the method is available for `impl Debug` here
|
= help: items from traits can only be used if the trait is in scope
help: trait `Debug` which provides `fmt` is implemented but not in scope; perhaps you want to import it
|
LL + use std::fmt::Debug;
|

error[E0599]: no method named `fmt` found for mutable reference `&mut impl Debug` in the current scope
--> $DIR/call_method_without_import.rs:26:11
|
LL | x.fmt(f);
| ^^^ method not found in `&mut impl Debug`
|
= help: items from traits can only be used if the trait is in scope
help: the following traits which provide `fmt` are implemented but not in scope; perhaps you want to import one of them
|
LL + use std::fmt::Binary;
|
LL + use std::fmt::Debug;
|
LL + use std::fmt::Display;
|
LL + use std::fmt::LowerExp;
|
and 5 other candidates

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0599`.
42 changes: 42 additions & 0 deletions tests/ui/impl-trait/call_method_without_import.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//! Test that opaque types only pick up methods from traits in their bounds
//! if the trait is imported.
//!
//! FIXME: always look through the bounds of an opaque type to see if there are
//! methods that could be called on any of the bound traits, irrespective of
//! imported traits.

//@ revisions: import no_import
//@[import] check-pass

oli-obk marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(import)]
use std::fmt::Debug as _;

fn foo(f: &mut std::fmt::Formatter<'_>) -> impl std::fmt::Debug {
if false {
let x = foo(f);
x.fmt(f);
//[no_import]~^ ERROR: no method named `fmt` found
}
()
}

fn foo1(f: &mut std::fmt::Formatter<'_>) -> impl std::fmt::Debug {
if false {
let x = &mut foo(f);
x.fmt(f);
//[no_import]~^ ERROR: no method named `fmt` found
}
()
}

// inconsistent with this
fn bar<T>(t: impl std::fmt::Debug, f: &mut std::fmt::Formatter<'_>) {
t.fmt(f);
}

// and the desugared version, of course
fn baz<T: std::fmt::Debug>(t: T, f: &mut std::fmt::Formatter<'_>) {
t.fmt(f);
}

fn main() {}
36 changes: 36 additions & 0 deletions tests/ui/impl-trait/method-resolution.current.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
error[E0599]: no method named `bar` found for struct `Bar<impl Sized>` in the current scope
--> $DIR/method-resolution.rs:23:11
|
LL | struct Bar<T>(T);
| ------------- method `bar` not found for this struct
...
LL | x.bar();
| ^^^ method not found in `Bar<impl Sized>`
|
= note: the method was found for
- `Bar<u32>`

error[E0391]: cycle detected when computing type of opaque `foo::{opaque#0}`
--> $DIR/method-resolution.rs:19:24
|
LL | fn foo(x: bool) -> Bar<impl Sized> {
| ^^^^^^^^^^
|
note: ...which requires type-checking `foo`...
--> $DIR/method-resolution.rs:23:9
|
LL | x.bar();
| ^
= note: ...which requires evaluating trait selection obligation `Bar<foo::{opaque#0}>: core::marker::Unpin`...
= note: ...which again requires computing type of opaque `foo::{opaque#0}`, completing the cycle
note: cycle used when computing type of `foo::{opaque#0}`
--> $DIR/method-resolution.rs:19:24
|
LL | fn foo(x: bool) -> Bar<impl Sized> {
| ^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0391, E0599.
For more information about an error, try `rustc --explain E0391`.
Loading