Closure return type not deduced from bounds if the type is wrapped.
In a tuple, for example:
fn call<R, F: FnOnce() -> R>(f: F) -> R {
f()
}
fn main() {
let _: (&[i32],) = call(|| (&[],));
}
AFAICT, we don't deduce that call::<$R, _>(|| (&[],)) expects (&[i32],) implies &[] expects &[i32], only (&[],) expects $R.
I don't think the wrapper is involved here (that's it, unlike the somewhat-similar #20841).
In the first example, you are actually invoking
call::<&String, _>and the coercion is done after the call.Ariel Ben-Yehuda at 2016-02-22 11:44:12
@arielb1 Oops, I reduced the testcase incorrectly (I've edited the description now). I'm not sure how to get this to cause issues without some sort of wrapper. Maybe the MIR can show where the coercion happens?
Eduard-Mihai Burtescu at 2016-02-22 11:57:01
@eddyb
I think I understand this. The type parameters passed to
callare still type-variables when the closure is checked, which means that the fn obligation isFnOnce() -> _. Asdeduce_expectations_from_expected_typeis keyed on the obligation, it only finds theFnOnce() -> _.The reason the coercion works without a closure is that we provide the "expected argument types". However, the expected argument types aren't related to the
FnOnceobligations.So this is actually pretty similar to #20841.
Ariel Ben-Yehuda at 2016-02-22 12:00:33
It looks like you can resolve this by changing it to this:
fn call<R, F: FnOnce() -> R>(f: F) -> R { f() } fn main() { - let _: (&[i32],) = call(|| (&[],)); + let _: (&[i32; 0],) = call(|| (&[],)); }Although I think it's still a bug.
Here's a playground with the change applied: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d29a9da04efaf4845b9bcd93ab426f13
Noah Lev at 2020-09-15 17:11:43