No, works as advertised. You are asking for the type to be inferred, which makes it not-a-coercion-site.
"(T, U)
to (T, V)
where U
coerces to V
" is not an allowed coercion type, or even cast.
// Ok
let z = ("bar", bar as fn(i32));
// error[E0605]: non-primitive cast:
// `(&'static str, fn(i32) {bar})` as `(&str, fn(i32))`
let z = ("bar", bar) as (&str, fn(i32));
Is it not? The Coercion sites section says:
That's why the inline version works -- each tuple field is a coercion site -- but it's not a coercion of (T, U)
to (T, V)
directly.
Sorry, I don't understand what you mean by that.
The non-inline version works as well, when all types are explicitly given. It only fails when the type of the callable is left to be inferred. This means that the problem is not with the tuple itself â the tuple field would be a coercion site (since its parent tuple is due to the annotated let
statement), and it is the _
type hole that prevents the coercion.
It's still not clear to me why. This is also an error:
Why is the first foo(("bar", bar))
call not an error? Both a let and a function argument are coercion sites. It seems to me that first legal foo
call is using a function argument as a coercion site, the second is using a let, and the third is using one or the other. I am assuming here that the "true" type of the bar
funptr is something which cannot be written out, so it has to be coerced to fn(i32)
.
That's still inline in the manner I meant...
let x :(&str, fn(i32)) = ("bar", bar);
// ^----------^
The literal (...)
tuple constructor in the source code makes the field sites coercion sites. The annotation on the left serves the same role as the annotation in the function argument, supplying target type(s).
The ("bar", bar)
as a whole does not coerce. The "bar"
and the bar
coerce.
Literal tuple constructors propagate coercions to the fields, but tuple type are not coercion types;[1] you can't coerce values that have tuple types.
outside of subtyping âŠī¸
bar
is in a place where it can be coerced to a function pointer.
// Coercion site annotated with (&str, fn(i32))
// vvvvvvvvvvvv
foo(("bar", bar));
/// ^^^^^ ^^^-- coercion site for fn(i32)
/// `-- coercion site for &str
The fully annotated let x : ...
works similarly.
You need a coercion site, but also a reason for the compiler to perform a coercion. A wildcard type annotation (_
) is not a strong enough reason. So in these examples, the compiler decides that the type of y.1
is the function item type,[1] not a function pointer.
let y = ("bar", bar);
let y: _ = ("bar", bar);
let y: (&str, _) = ("bar", bar);
...and you also need the coercion to be allowed; you can't coerce tuple values, so y
cannot coerce here:
foo(y); // does not compile
// ^-- Coercion site annotated with (&str, fn(i32))
But this works similarly to foo(("bar", bar))
:
foo((y.0, y.1));
Here's another workaround:
let y = ("bar", bar as _);
foo(y);
The explicit cast -- even with the wildcard type -- is enough for the compiler to defer deciding y.1
's type until it can figure out what you meant.
Function item types cannot be written out. But you can use generics instead of function pointers, depending on the situation.
fn quz<F: FnMut(i32)>(_: (&str, F)) {}
fn main() {
let y = ("bar", bar);
quz(y);
}
i.e. the type of the expression
bar
âŠī¸
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.