Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upCannot infer closure type with higher-ranked lifetimes inside Box::new #20841
Comments
mzabaluev
added a commit
to gi-rust/grust
that referenced
this issue
Jan 10, 2015
kmcallister
added
A-typesystem
A-closures
labels
Jan 11, 2015
This comment has been minimized.
This comment has been minimized.
|
Triage: updated code fn do_async<F>(_cb: Box<F>) where F: FnOnce(&i32) {
}
fn do_async_unboxed<F>(cb: F) where F: FnOnce(&i32) {
do_async(Box::new(cb))
}
fn main() {
do_async_unboxed(|x| { println!("{}", *x); }); // Ok
do_async(Box::new(|x| { println!("{}", *x); })); // ERROR the type of this value must be known in this context
} |
arielb1
added
the
T-compiler
label
Nov 22, 2015
arielb1
added
the
I-nominated
label
Nov 22, 2015
This comment has been minimized.
This comment has been minimized.
|
From my investigation, the problem is that we don't relate the return type of |
This comment has been minimized.
This comment has been minimized.
|
Nominating as this is makes some API patterns horribly non-ergonomic. |
nikomatsakis
added
the
T-lang
label
Dec 1, 2015
This comment has been minimized.
This comment has been minimized.
|
triage: P-medium |
This comment has been minimized.
This comment has been minimized.
|
I agree we could probably do better here. I'm not sure what precisely is going on or the current state of this coercion code though. |
This comment has been minimized.
This comment has been minimized.
|
triage: P-medium |
rust-highfive
added
P-medium
and removed
I-nominated
labels
Dec 17, 2015
This comment has been minimized.
This comment has been minimized.
// Works:
fn foo<F: Fn(f32) -> f32>(_: F) {}
foo(|x| x.sin())
// Why it works: the inference variables look like this:
foo::<$F>((|x: $A| x.sin()): $F)
// Because $F: Fn(f32) -> f32, we can deduce $A: f32.// Doesn't work:
fn bar<F: Fn(f32) -> f32>(_: Option<F>) {}
bar(Some(|x| x.sin()))
// Why it doesn't work: the inference variables look like this:
bar::<$F>(Some::<$T>((|x: $A| x.sin()): $T): Option<$F>)
// Because Some: T -> Option<T>, we know that $T = $F.
// But they are both inference variables, so we don't replace
// one with the other, and $T: Fn(f32) -> f32 doesn't exist.If my analysis is correct, it should be possible to fix this bug by computing inference variable equivalence via union-find instead of using simple equality. |
arielb1
referenced this issue
Jan 10, 2016
Closed
Cannot coerce to FnBox with references in arguments #28222
This comment has been minimized.
This comment has been minimized.
|
Except that the variables are only related via a coercion. |
This comment has been minimized.
This comment has been minimized.
|
That looks like a case of things being so loosely coupled they fall apart. |
This comment has been minimized.
This comment has been minimized.
|
@arielb1 There's no coercion magic going on, this is the "expected" type being propagated down. Coercions are applied after the type is known. |
This comment has been minimized.
This comment has been minimized.
|
I mean, we don't equate |
This comment has been minimized.
This comment has been minimized.
|
@arielb1 We do to obtain the expected type for the arguments of a call. |
This comment has been minimized.
This comment has been minimized.
|
That would be a subtype relation, which is destroyed by the |
This comment has been minimized.
This comment has been minimized.
|
@arielb1 Let's try to be clearer using pseudosyntax: // Initial expression.
bar(Some((|x| x.sin())))
// Add type variables for bar.
bar::<$F>(Some((|x| x.sin())))
// Propagate expected type from signature of bar.
bar::<$F>(Some((|x| x.sin())) expects Option<$F>)
// Add type variables for Some.
bar::<$F>(Some::<$T>((|x| x.sin())))
// Propagate expected type from signature of Some.
bar::<$F>(Some::<$T>((|x| x.sin()) expects $T) expects Option<$F>)Well, that's embarrassing, turns out I was being unreasonable. A relationship between Presumably it might be possible to end up with: bar::<$F>(Some::<$T>((|x| x.sin()) expects $F) expects Option<$F>)What confused me was that the following snippet fn foo<F: Fn(f32) -> f32>(_: F) {}
fn id<T>(x: T) -> T {x}
foo(id(|x| x.sin()))Given that it doesn't actually work, it's a better testcase. foo::<$F>(id::<$T>((|x| x.sin()) expects $F) expects $F)Then that would work, but consider: fn foo<F>(_: F) {}
fn id<T: Fn(f32) -> f32>(x: T) -> T {x}
foo(id(|x| x.sin()))Where @arielb1 @nikomatsakis Would it make sense to have a set of inference variable "assignments" used for the expected type? |
This comment has been minimized.
This comment has been minimized.
|
That might fix this, but it may cause confusing issues if a coercion were actually to occur. Maybe have hints solely for closure inference? That looks like a hack. |
This comment has been minimized.
This comment has been minimized.
|
@arielb1 Nothing other than closure inference looks at bounds which refer to the expected type, AFAICT. |
arielb1
referenced this issue
Feb 22, 2016
Open
Closure return type not deduced from bounds if the type is wrapped. #31815
brson
added
P-low
E-medium
and removed
P-medium
labels
Aug 25, 2016
brson
added
the
C-enhancement
label
Aug 25, 2016
This comment has been minimized.
This comment has been minimized.
|
Triage: not aware of any movement on this issue |
mzabaluev commentedJan 10, 2015
In the code below, type inference works in the first line of
main(), but fails in the second one. Note also that the "kind" of the closure has to be given with explicit syntax when insideBox::new().