First reported at https://github.com/alexcrichton/futures-rs/issues/97
xx.rs:
use futures::*;
pub fn yy() -> BoxFuture<u32, ::std::io::Error> {
done(Ok(1)).boxed()
}
main.rs:
extern crate futures;
mod xx;
use futures::Future;
fn main() {
let f = xx::yy();
println!("wait: {:?}", f.wait());
}
This code works.
If use futures::Future
is commented out in main.rs
, compiler complains:
src/main.rs:10:30: 10:34 error: the trait bound `futures::Future<Error=std::io::Error, Item=u32> + Send: std::marker::Sized` is not satisfied [E0277]
src/main.rs:10 println!("wait: {:?}", f.wait());
^~~~
<std macros>:2:27: 2:58 note: in this expansion of format_args!
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std macros>)
src/main.rs:10:5: 10:38 note: in this expansion of println! (defined in <std macros>)
src/main.rs:10:30: 10:34 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:10:30: 10:34 note: `futures::Future<Error=std::io::Error, Item=u32> + Send` does not have a constant size known at compile-time
error: aborting due to previous error
error: Could not compile `futures-rs-td`.
I'm not sure if is it a bug, or just a usability problem, is it in futures-rs or in rust language, but it is hard to understand error message.
rustc 1.11.0 (9b21dcd6a 2016-08-15), futures-rs from master
cc @stepancheg
cc @jonathandturner
cc @nikomatsakis
This is _seriously_ confusing. I just spend 30 minutes trying to figure it out before googling and finding this.
I believe what is happening is this:
<Box<Future> as Future>::wait(&f)
(presuming wait()
is an &self
method)<Future as Future>::wait(&*f)
Self
type is Future
, and I imagine that wait()
is defined with where Self: Sized
Given the popularity of this pattern (e.g., iterators work the same way), it's probably worth trying to tailor an error message for this case if we can.
I imagine something like this:
where Self: Sized
messageThe trick is...what do we say in this scenario? Advising to import the trait may not be a good fix, though we could look for trait impls on Box<Trait>
and/or &Trait
etc and only give the message in that case.
Giving the existing "import the trait" error would at least be an improvement.
Marking as a diagnostics issue. cc @rust-lang/compiler, perhaps we could prioritize this? It's possible that even small wins ("import the trait") here would be very good. Even just almost always doing this might be a lot better if given with the right wording.
OK, so, the challenge here is that method resolution succeeds. I am a bit torn. Perhaps the easiest (and maybe even best) way to solve this is to modify method resolution itself to check for this particular case. That is, when method resolution succeeds, if this is a trait method, we could quickly scan the where-clauses for the method, looking specifically for Self: Sized
. If we find it, we can remove it from the list and issue a customized error. I think this is how I would go about it.
I'm out of time this morning for writing detailed mentoring instructions, but let me give a few pointers. I'm happy to elaborate further in the future. The method searching code is found in this module. It works in two phases: the first phase, probing, finds which method applies. That doesn't have to change here, I think.
The second phase, confirmation, does a bit of further work. Here is the implementation of the confirm_method()
function. As part of its work, it invokes add_obligations()
, which is what records the where clauses (later on, we will check that they are satisfied).
So basically my proposal is to interject there and detect this particular case and issue a custom error.
triage: P-medium
@raphlinus and I ran into this bug this morning when using and_then
on a BoxFuture
without importing the trait. It took us 10+ minutes working together and replicating a skeleton of our code in play.rust-lang.org and looking for differences before we figured it out.
I think @nikomatsakis's solution would have worked well for us. If it detects you trying to call a trait method with a Self: Sized
bound it could jump up a deref-level and use the same logic that failed method resolution normally uses to suggest traits applicable to Box<Future>
you might want to import, which would find that futures::Future
has an and_then
method.
Most helpful comment
This is _seriously_ confusing. I just spend 30 minutes trying to figure it out before googling and finding this.