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

Confusing compiler error message when attempting to pass a trait object to a function using immutable reference #37914

Closed
hniksic opened this issue Nov 21, 2016 · 10 comments · Fixed by #65077 or #106363
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@hniksic
Copy link
Contributor

hniksic commented Nov 21, 2016

The following code fails to compile because the reference to the iterator trait object must be mutable, to enable advancing the iterator:

fn test(t: &Iterator<Item=&u64>) -> u64 {
     *t.min().unwrap()
}

fn main() {
     let array = [0u64];
     test(&array.iter());
}

When the problem is fixed by declaring the trait object as mutable, the code compiles and runs just fine:

fn test(t: &mut Iterator<Item=&u64>) -> u64 {
     *t.min().unwrap()
}

fn main() {
     let array = [0u64];
     test(&mut array.iter());
}

Understanding the problem, I would expect the error message for the first snippet to be something along the lines of "error: Iterator<Item=&u64>::next requires a mutable reference". Instead, the compilation failed with the following error:

error[E0277]: the trait bound `std::iter::Iterator<Item=&u64>: std::marker::Sized` is not satisfied
 --> iter.rs:2:9
  |
2 |      *t.min().unwrap()
  |         ^^^ trait `std::iter::Iterator<Item=&u64>: std::marker::Sized` not satisfied
  |
  = note: `std::iter::Iterator<Item=&u64>` does not have a constant size known at compile-time

error: aborting due to previous error

Being a beginner in Rust, this error message threw me off. First, I couldn't understand why Rust was insisting that the object is unsized, when the object was declared to accept a reference (fat pointer) to a trait, or that was at least my intention. (I still don't understand this part.)

More importantly, there was no hint that the problem could be resolved simply by changing & to &mut in declaration and invocation. Once I realized that, the change was obvious and easy, but the compiler's error message did not help me understand the problem.

@bjorn3
Copy link
Member

bjorn3 commented Nov 21, 2016

Iterator::min consumes self, which requires the size of self to be known comile time. If you have a non mutable reference rustc will deref the reference to get something it can call .min on. However if you have a mutable reference rustc knows that there is a implementation of Iterator for it without having to dereference it, so you dont have a unsized value.

@hniksic
Copy link
Contributor Author

hniksic commented Nov 21, 2016

Thanks for the clarification. Could the compiler's diagnostics check, "if only this reference to trait were mutable, it would no longer be unsized", and provide a hint to the user? In many other cases rustc does an excellent job in guiding the user toward correct code.

@Mark-Simulacrum Mark-Simulacrum added the A-diagnostics Area: Messages for errors, warnings, and lints label May 16, 2017
@Mark-Simulacrum Mark-Simulacrum added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jul 26, 2017
@hniksic
Copy link
Contributor Author

hniksic commented Dec 19, 2017

The message has changed in the meantime, but it still doesn't show how to fix the problem:

   Compiling playground v0.0.1 (file:///playground)
error: the `min` method cannot be invoked on a trait object
 --> src/main.rs:2:9
  |
2 |      *t.min().unwrap()
  |         ^^^

error: aborting due to previous error

It would be nice if the message at least hinted at mutability as the source of the problem.

@shepmaster
Copy link
Member

shepmaster commented Feb 16, 2018

This problem surfaced again on Stack Overflow, for the same underlying reason: &Iterator.

An interesting point is that calling next directly does have a good error:

fn test(t: &Iterator<Item = &u64>) {
    t.next();
}
error[E0596]: cannot borrow immutable borrowed content `*t` as mutable
 --> src/main.rs:2:5
  |
1 | fn test(t: &Iterator<Item = &u64>) {
  |            ---------------------- use `&mut Iterator<Item = &u64>` here to make mutable
2 |     t.next();
  |     ^ cannot borrow as mutable

@estebank
Copy link
Contributor

Current output:

error: the `min` method cannot be invoked on a trait object
 --> src/main.rs:2:9
  |
2 |      *t.min().unwrap()
  |         ^^^

@estebank
Copy link
Contributor

Current output:

error: the `min` method cannot be invoked on a trait object
 --> src/main.rs:2:9
  |
2 |      *t.min().unwrap()
  |         ^^^
  |
  = note: you need `&mut dyn std::iter::Iterator<Item = &u64>` instead of `&dyn std::iter::Iterator<Item = &u64>`

@acshi
Copy link

acshi commented Apr 28, 2020

In the case of noisy iterator types, I didn't see the difference between "&mut Iter..." and "&Iter..." until I found this issue page!

Would it be possible to really emphasize the mutability difference in the help message?

help: the trait `std::iter::Iterator` is not implemented for `&std::slice::Iter<'_, ...>`
help: try using a mutable reference:
help: `std::iter::Iterator` is implemented for `&mut std::slice::Iter<'_, ...>`, but not for `&std::slice::Iter<'_, ...>`

@estebank estebank reopened this Apr 28, 2020
@crlf0710 crlf0710 added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Jun 11, 2020
@estebank
Copy link
Contributor

estebank commented Jan 2, 2023

Triage: the current output still mentions that you need &mut instead of &, but we have added more output which makes it harder to notice and ideally we'd want a structured suggestion for it.

error: the `min` method cannot be invoked on a trait object
    --> f57.rs:2:9
     |
2    |      *t.min().unwrap()
     |         ^^^
     |
    ::: /Users/ekuber/workspace/rust/library/core/src/iter/traits/iterator.rs:3012:15
     |
3012 |         Self: Sized,
     |               ----- this has a `Sized` requirement
     |
     = note: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`

Edit: I believe this output will allow us to close this ticket:
Screen Shot 2023-01-01 at 8 51 02 PM

compiler-errors added a commit to compiler-errors/rust that referenced this issue Jan 9, 2023
…r=Nilstrieb

Structured suggestion for `&mut dyn Iterator` when possible

Fix rust-lang#37914.
compiler-errors added a commit to compiler-errors/rust that referenced this issue Jan 9, 2023
…r=Nilstrieb

Structured suggestion for `&mut dyn Iterator` when possible

Fix rust-lang#37914.
@bors bors closed this as completed in 1eb828e Jan 9, 2023
@hniksic
Copy link
Contributor Author

hniksic commented Jan 9, 2023

Thanks to everyone working to improve this over the years.

@bors The primary message "the min method cannot be invoked on a trait object" still seems at least somewhat confusing, as min() can and does apply to trait objects. The underlying issue was explained by @bjorn3 in this comment, but it seems quite hard to arrive to it from the compiler message.

I can file a separate ticket that concentrates on this issue, as the part where the compiler identifies that a mutable ref is needed is clearly covered now.

@estebank
Copy link
Contributor

estebank commented Jan 9, 2023

I can file a separate ticket that concentrates on this issue, as the part where the compiler identifies that a mutable ref is needed is clearly covered now.

We can reopen this one, of course, but opening a new one with a more direct description (and a link to this one) will be easier to keep track of and understand when it is "done". Thank you for all your reports! They are incredibly important in improving Rust!

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 C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
7 participants