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

Trait bound is ignored #65149

Closed
fuchsnj opened this issue Oct 6, 2019 · 10 comments
Closed

Trait bound is ignored #65149

fuchsnj opened this issue Oct 6, 2019 · 10 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-trait-system Area: Trait system C-bug Category: This is a bug. D-confusing Diagnostics: Confusing error or lint that should be reworked. F-arbitrary_self_types `#![feature(arbitrary_self_types)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@fuchsnj
Copy link

fuchsnj commented Oct 6, 2019

I have a simple program below that is trying to call poll_next on a T: Stream. The compiler seems to ignore the trait bound, and suggests adding the exact trait bound that is already in use.

This is using the current beta rust version:
rustc 1.39.0-beta.5 (fa5c2f3e5 2019-10-02)

pub struct StreamForwarder<T> {
    upstream: T,
}

impl<T: futures_core::stream::Stream> Stream for StreamForwarder<T> {
    type Item = ();

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        self.upstream.poll_next()
    }
}
error[E0599]: no method named `poll_next` found for type `T` in the current scope
  --> src/main.rs:13:23
   |
13 |         self.upstream.poll_next()
   |                       ^^^^^^^^^ method not found in `T`
   |
   = help: items from traits can only be used if the type parameter is bounded by the trait
help: the following trait defines an item `poll_next`, perhaps you need to restrict type parameter `T` with it:
   |
9  | impl<T: futures_core::stream::Stream + futures_core::stream::Stream> Stream for StreamForwarder<T> {
   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0599`.
error: could not compile `poll_next_bug`.

A complete git repo reproducing the issue is here: https://github.com/fuchsnj/poll_next_bug
(remember to run rustup override set beta)

@jonas-schievink jonas-schievink added A-diagnostics Area: Messages for errors, warnings, and lints C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-trait-system Area: Trait system labels Oct 6, 2019
@nagisa
Copy link
Member

nagisa commented Oct 7, 2019

Seems like it is related entirely to the "arbitrary" self types thing. poll_next requires Pin<_> as a self, and self.upstream is not Pin. We likely never encountered this before Pin, because with & and &mut, "receivers" were autoref'd.

MCVE:

use std::pin::Pin;

pub trait Foo {
    fn pin_recv(self: Pin<&mut Self>);
}

impl Foo for u64 {
    fn pin_recv(self: Pin<&mut u64>) {}
}

pub struct Wrapped<T> {
    num: T,
}

impl<T: Foo> Foo for Wrapped<T> {
    fn pin_recv(self: Pin<&mut Self>) {
        self.num.pin_recv()
        // correct: `Pin::new(&mut self.num).pin_recv()`
    }
}

@nagisa
Copy link
Member

nagisa commented Oct 7, 2019

This also affects other stable "receivers" that are not subject to autoref, such as Rc or Arc.

cc #56805 @mikeyhew

@Rantanen
Copy link
Contributor

Rantanen commented Oct 10, 2019

Another example

trait Bounded {
    const COUNT : usize;
}

fn make_array<B : Bounded>() -> [bool; B::COUNT] {
    [false; B::COUNT]
}

Playground

(Also note the formatting error in the text - rustc inserts the new bound after the current type, assuming that's where the colon is. Thus in this specific example the suggestion has invalid syntax due to the space before the colon in the code.)

@fenhl
Copy link
Contributor

fenhl commented Oct 25, 2019

Is there a way to work around this?

@sfackler
Copy link
Member

@fenhl see nagisa's comment above. poll_next must be called on Pin<&mut T>, not T.

@estebank estebank added D-confusing Diagnostics: Confusing error or lint that should be reworked. F-arbitrary_self_types `#![feature(arbitrary_self_types)]` labels Nov 8, 2019
@estebank
Copy link
Contributor

Current output, we no longer provide the incorrect suggestions:

error[E0599]: no method named `poll_next` found for type parameter `T` in the current scope
  --> src/lib.rs:14:23
   |
14 |         self.upstream.poll_next()
   |                       ^^^^^^^^^ method not found in `T`
   |
   = help: items from traits can only be used if the type parameter is bounded by the trait

This is another case of #69069.

@nagisa
Copy link
Member

nagisa commented Feb 18, 2020

Should we close the duplicates? And also this issue, given that we no longer suggest wrong?

@estebank
Copy link
Contributor

Should we close the duplicates?

Maybe, but let's make sure we link them up.

And also this issue, given that we no longer suggest wrong?

No, we need to improve the output when dealing with arbitrary self types. The current output is at least no longer wrong but it is misleading and actively confusing for anyone not intimately knowledgeable about the language.

Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Feb 27, 2020
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Feb 28, 2020
bors added a commit that referenced this issue Feb 29, 2020
Add more context to E0599 errors

Point at the intermediary unfulfilled trait bounds.

Fix #52523, fix #61661, cc #36513, fix #68131, fix #64417, fix #61768, cc #57457, cc #9082, fix #57994, cc #64934, cc #65149.
@SkiFire13
Copy link
Contributor

@Rantanen your example gives me a different error.

error[E0599]: no associated item named `COUNT` found for type parameter `B` in the current scope
 --> src/lib.rs:5:43
  |
5 | fn make_array<B : Bounded>() -> [bool; B::COUNT] {
  |                                           ^^^^^ associated item not found in `B`
  |
  = help: items from traits can only be used if the type parameter is bounded by the trait

This example instead:

trait Bounded {
    const COUNT : usize;
}

fn make_array<B : Bounded>() -> [bool; <B as Bounded>::COUNT] {
    [false; B::COUNT]
}

gives the following error:

error[E0277]: the trait bound `B: Bounded` is not satisfied
 --> src/lib.rs:5:40
  |
2 |     const COUNT : usize;
  |     -------------------- required by `Bounded::COUNT`
...
5 | fn make_array<B : Bounded>() -> [bool; <B as Bounded>::COUNT] {
  |                                        ^^^^^^^^^^^^^^^^^^^^^ the trait `Bounded` is not implemented for `B`
  |
help: consider further restricting this bound
  |
5 | fn make_array<B : Bounded + Bounded>() -> [bool; <B as Bounded>::COUNT] {
  |                           ^^^^^^^^^

Playground

Also notice that this example isn't related to arbitrary self types but gives the same wrong suggestion.

@estebank
Copy link
Contributor

We now suggest an appropriate fix for the original report (although a few extra changes are needed to get to working code, the suggestions lead you all the way there):

error[E0599]: no method named `pin_recv` found for type parameter `T` in the current scope
  --> src/lib.rs:17:18
   |
4  |     fn pin_recv(self: Pin<&mut Self>);
   |        --------       -------------- the method might not be found because of this arbitrary self type
   |        |
   |        the method is available for `Pin<&mut T>` here
...
17 |         self.num.pin_recv()
   |                  ^^^^^^^^ method not found in `T`
   |
help: consider wrapping the receiver expression with the appropriate type
   |
17 |         Pin::new(&mut self.num).pin_recv()
   |         +++++++++++++         +

We no longer suggest adding a bound when it was used in a const expression:

error: generic parameters may not be used in const operations
 --> src/lib.rs:5:40
  |
5 | fn make_array<B : Bounded>() -> [bool; B::COUNT] {
  |                                        ^^^^^^^^ cannot perform const operation using `B`
  |
  = note: type parameters may not be used in const expressions

error: constant expression depends on a generic parameter
 --> src/lib.rs:6:13
  |
6 |     [false; B::COUNT]
  |             ^^^^^^^^
  |
  = note: this may fail depending on what value the parameter takes
error: generic parameters may not be used in const operations
 --> src/lib.rs:5:41
  |
5 | fn make_array<B : Bounded>() -> [bool; <B as Bounded>::COUNT] {
  |                                         ^ cannot perform const operation using `B`
  |
  = note: type parameters may not be used in const expressions

error: constant expression depends on a generic parameter
 --> src/lib.rs:6:13
  |
6 |     [false; B::COUNT]
  |             ^^^^^^^^
  |
  = note: this may fail depending on what value the parameter takes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-trait-system Area: Trait system C-bug Category: This is a bug. D-confusing Diagnostics: Confusing error or lint that should be reworked. F-arbitrary_self_types `#![feature(arbitrary_self_types)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

8 participants