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
Implicit int to float conversion in function arguments fails when using arithmetic operations #17074
Comments
A potential workaround that might work in some situations is to use inline functions with op_Explicit constraint (like for example so): // f: 'a (requires static member op_Explicit )
let inline a f = float f
let r0 = a 1.0
let r1 = a 1
let r2 = a (10 / 2) // No more error; it compiles
let r3 =
let x = 10 / 2
a x
let r4 = 10 / 2 |
It's even more nuanced than I thought. The range of the error is weird because it actually belongs to
These make it much harder to fix tbh. |
I got some more test cases: let a (f: float) = f
let inline div x y = x / y
let divInts x y = x / y
let r0 = a 1.0
let r1 = a 1
let r2 = a (10 / 2) // Error: the type 'float' does not match the type 'int'
let r3 =
let x = 10 / 2
a x
let r4 = 10 / 2
// > It's not limited to operators, most of the complex expressions will fail.
// These don't fail:
let r5 = a ((fun () -> 10 / 2) ())
let r6 = a (let x = 10 / 2 in x)
let r7 = a (int (1 * 10 / 2 * 1))
// Important: Error is shown in IDE, but
// in FSI, it compiles and evaluates to 5.0 (ok),
let r8 = a (divInts 10 99) // Error (IDE only !!): the type 'float' does not match the type 'int'
let r9 = a (div 10 2) // Error: the type 'float' does not match the type 'int' |
Ok, I think I understand; it's overload resolution in combination of an operator (which also involves overload resolution). So inference in that case somehow requires a "best match" strategy respecting implicit conversion, etc.? Huh... |
It's multiple things, yeah. The main one in original issue is "we restricted the type first, then try to find corresponding let r5 = a ((fun () -> 10 / 2) ())
let r6 = a (let x = 10 / 2 in x)
let r7 = a (int (1 * 10 / 2 * 1)) r5 - we defined a function, and reduced it already, so let r5 = a ((fun x -> 10 / x) 2) r6 - well, pretty much the same reason as r7 - again, same as two above. I'm not entirely sure why don't we do anything in the |
I'm pretty sure this is caused by the same "language feature" as #17062, which is specifics of "standard" operators resolution in F#, for example, this |
@vzarytovskii Can this be consider a regression ? Edit: This appeared during the AmplifyingF# Lectures https://amplifyingfsharp.io/fsharp-essentials/ too and it was confusing for the students. |
Not sure about it, it's been there for a while, and not recent (sharplab has it). Probably existed since conversions were introduced? I'm also not entirely sure how fix would look like. |
Reading point 1.1.3 Making Types Simple seems like this is not as the spec describes.
|
Implicit conversions are not part of the spec, they were introduced in F# 6 or 7, and obviously it doesn't work like that. It's a bug which is related to conversions and operators, and not a regression. |
Agreed that it doesn’t include the implicit conversions. But the principle still stand that once you add a type annotation to function parameter this should be the type used in its body right ?
Right. I guess this is the RFC https://github.com/fsharp/fslang-design/blob/main/FSharp-6.0/FS-1093-additional-conversions.md |
Yes, and it uses it, it uses it to determine return type of op_Division - a float, but real type is int, and hence the error message and range pointing to last digit. |
When a function
It appears that implicit conversion from integer to float is not working as expected when passing an integer that is an expression involving (somehow) arithmetic operations. This behavior is inconsistent other cases (like shown in the example).
I say: The expr at
r2
should compile, too, like all other exprs.See also here: https://twitter.com/SchlenkR/status/1781698130578211247
Note My experience is that this bug is a real pain for beginners, and it is extremely annoying when (e.g.) mapping values at API layers, etc.
Thanks
The text was updated successfully, but these errors were encountered: