Skip to content
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

Better diagnostic for calling Method(x = 0.5) when takes bool #9517

Open
abelbraaksma opened this issue Jun 20, 2020 · 5 comments
Open

Better diagnostic for calling Method(x = 0.5) when takes bool #9517

abelbraaksma opened this issue Jun 20, 2020 · 5 comments
Labels
Area-Diagnostics mistakes and possible improvements to diagnostics Feature Request
Milestone

Comments

@abelbraaksma
Copy link
Contributor

abelbraaksma commented Jun 20, 2020

I hope this is just one of those gotcha's that I sometimes have when I stare too long at the screen. With NUnit, this doesn't compile:

let x = 0.5
Asssert.IsTrue(x = 0.5)   // FS0505
Asssert.IsFalse(x = 0.5)   // FS0505

The error:

FS0505: The member or object constructor 'IsTrue' does not take 0 argument(s). An overload was found taking 1 arguments.

However, these compile fine:

let x = 0.5
not(x = 0.5)
Assert.IsTrue(0.5 = 0.5)
Assert.IsFalse(0.4 = 0.5)
Assert.IsTrue(x <> 0.4)
Assert.IsFalse(x <> 0.5)
Assert.IsFalse((3.0 + 4.0) = result)

Expected behavior

I figured the above should not give a compile error.

Actual behavior

They raise FS0505. And it says "does not take 0 arguments", that doesn't seem right.

Known workarounds

Add an extra pair of parens.

Related information

As far as I can remember, any place that takes boolean can take a compare-operator, but apparently that isn't true for =, but only if the expression involves a variable identifier.

I have not checked other cases than the ones mentioned above, though I suspect it has something to do with the overload resolution, but that doesn't explain why it works with one operator, but not the other.

Or I'm totally missing the obvious 😆

@abelbraaksma
Copy link
Contributor Author

abelbraaksma commented Jun 20, 2020

Related (the overload exists):

image

Assert.IsTrue(result <> 0.66403677026784891, "msg") // works
Assert.IsTrue(result = 0.66403677026784891, "msg") // fails with above message

@abelbraaksma
Copy link
Contributor Author

abelbraaksma commented Jun 20, 2020

Keeps getting weirder. This works:

let result = ref 0.0
result := Operators.tanh 0.8
Assert.IsTrue(!result = 0.66403677026784891)

But this doesn't, and gives a really weird error:

let x = 0
Assert.IsTrue(x = 12)

image

And:

image

image

The error comes twice:

error FS0001: This expression was expected to have type� 'bool' �but here has type� 'int'
error FS0001: This expression was expected to have type� 'bool' �but here has type� 'int'

I should add that all this is in FSharp.Core.UnitTests, which uses a shadowing shim for the Assert.XXX methods in exactly the same namespace as NUnit. I'll try to get it down to something more manageable.

@Happypig375
Copy link
Member

Because Assert.IsTrue(x = 0.5) is a named argument. Parenthesize x = 0.5 to avoid this error.

@abelbraaksma
Copy link
Contributor Author

abelbraaksma commented Jun 21, 2020

Because Assert.IsTrue(x = 0.5) is a named argument. Parenthesize x = 0.5 to avoid this error.

@Happypig375, nice observation (the workaround I mentioned in the issue, though). The other workaround is to use 0.5 = x, I just found. But I still think it's a bug:

  1. There's no named argument named x, nor a property
  2. The error says I pass in "0 arguments", which is clearly wrong (when the type is float)
  3. When the type is int the error changes to the type error

I noticed that, only if I use the named argument correctly, as with Assert.IsTrue(condition = 0.5) I get a somewhat useful error:

Possible overload: 'Assert.IsTrue(condition: bool) : unit'. Type constraint mismatch. The type
'float'
is not compatible with type
'bool'

But even that error suggests nothing about the named argument being wrong.

However, the F# compiler does have an error specific for this case, namely:

type TryOut =
    static member Works(condition: bool) = ()
module X = 
    x = 0
    TryOut.Works(x = 0)

error FS0495: The member or object constructor 'Works' has no argument or settable return property 'x'. The required signature is static member TryOut.Works : condition:bool -> unit.

But if you use the wrong type with the correct name, you now get a correct error, though it's a confusing one:

image

I think in all these cases, the FS0495 should have been thrown, except perhaps for the last case above, which could say something like settable property or named argument 'condition' expects a bool argument, given an int argument.

This behavior appears to be like this since at least 2014 (I checked older VS), I'm surprised I only encounter it now. I'd like to suggest one or both solutions:

  • Improve the errors here to always mention the named argument
  • Allow = to evaluate to a boolean instruction in the absence of a named argument with the same name (this is backward compat safe, as it only solves error scenarios)

@abelbraaksma abelbraaksma changed the title Calling Assert.IsTrue(x = 0.5) raises FS0505, but Assert.IsTrue(x <> 0.5) is fine, as is Assert.IsTrue(0.5 = 0.5) Calling aBoolMethod(x = 0.5) raises FS0505, but no error for aBoolMethod(x <> 0.5) or aBoolMethod(0.5 = 0.5) Jun 27, 2020
@dsyme
Copy link
Contributor

dsyme commented Aug 24, 2020

Improve the errors here to always mention the named argument

Of the options above, we should do this (improve the error rather than accept new programs based on named argument analysis)

@dsyme dsyme changed the title Calling aBoolMethod(x = 0.5) raises FS0505, but no error for aBoolMethod(x <> 0.5) or aBoolMethod(0.5 = 0.5) Better diagnostic for calling Method(x = 0.5) when takes bool Mar 4, 2022
@dsyme dsyme added the Area-Diagnostics mistakes and possible improvements to diagnostics label Apr 20, 2022
@vzarytovskii vzarytovskii moved this to Not Planned in F# Compiler and Tooling Jun 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Diagnostics mistakes and possible improvements to diagnostics Feature Request
Projects
Status: New
Development

No branches or pull requests

5 participants