Skip to content

Conversation

@forki
Copy link
Contributor

@forki forki commented Jun 24, 2016

fixes #1280

image

@forki
Copy link
Contributor Author

forki commented Jun 24, 2016

ok the error shows this is harder than expected.

@forki forki force-pushed the record-1280 branch 2 times, most recently from 5b03bf3 to 41266e9 Compare June 24, 2016 10:22
@forki forki changed the title WIP: Better error message when a record was given Better error message when a record was given Jun 24, 2016
@forki
Copy link
Contributor Author

forki commented Jun 24, 2016

ready for review

@KevinRansom
Copy link
Contributor

@forki @dsyme
I think the compiler is actually displaying the wrong error message for this scenario.
The record definition is fine, the problem is that the argument is not incompatible with Record it's that it is incompatible with list.

Please see samples below for reasoning.

type Record = {field1:int; field2:int}  
let doSomething (xs) = List.map (fun {field1=x} -> x) xs  


- //If we call the code correctly it might look like this:
- doSomething [{Record.field1=0; Record.field2=0}] ;;
val it : int list = [0]
>
- //or this:
- doSomething [{field1=0; field2=0}] ;;
val it : int list = [0]
>
- //or this:
- doSomething [{Record.field1=0; field2=0}] ;;
val it : int list = [0]
>

So to introduce the bug, it is that the argument to doSomething is not a list:

- //introduce bug, not a list it might look like this:
- doSomething {Record.field1=0; Record.field2=0} ;;

  doSomething {Record.field1=0; Record.field2=0} ;;
  ------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(7,13): error FS0001: This expression was expected to have type
    'Record list'
but here has type
    'Record'
>
- //or this:
- doSomething {field1=0; field2=0} ;;

  doSomething {field1=0; field2=0} ;;
  ------------^^^^^^^^^^^^^^^^^^^^

stdin(10,13): error FS1129: This expression was expected to have type 'Record list' but here an incompatible record type was given.
>
- //or this:
- doSomething {Record.field1=0; field2=0} ;;

  doSomething {Record.field1=0; field2=0} ;;
  ------------^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(13,13): error FS1129: This expression was expected to have type 'Record list' but here an incompatible record type was given.
>

We see that for the first error we get a clear actionable accurate message:

stdin(77,13): error FS0001: This expression was expected to have type
    Record list
but here has type
    Record

But the other two entries, give a bogus error message:

stdin(13,13): error FS1129: This expression was expected to have type 'Record list' but here an incompatible record type was given.
>

@forki
Copy link
Contributor Author

forki commented Jun 25, 2016

Yes, I thought about raising a proper type unification error. But it wasn't
available at this position. I need to rewrite a bit more to make that work,
but I could try.
On Jun 25, 2016 1:30 PM, "Kevin Ransom (msft)" notifications@github.com
wrote:

@forki https://github.com/forki @dsyme https://github.com/dsyme
I think the compiler is actually displaying the wrong error message for
this scenario.
The record definition is fine, the problem is that the argument is not
incompatible with Record it's that it is incompatible with list.

Please see samples below for reasoning.

type Record = {field1:int; field2:int}
let doSomething (xs) = List.map (fun {field1=x} -> x) xs

  • //If we call the code correctly it might look like this:
  • doSomething [{Record.field1=0; Record.field2=0}] ;;
    val it : int list = [0]
  • //or this:
  • doSomething [{field1=0; field2=0}] ;;
    val it : int list = [0]
  • //or this:
  • doSomething [{Record.field1=0; field2=0}] ;;
    val it : int list = [0]

So to introduce the bug, it is that the argument to doSomething is not a
list:

  • //introduce bug, not a list it might look like this:

  • doSomething {Record.field1=0; Record.field2=0} ;;

    doSomething {Record.field1=0; Record.field2=0} ;;
    ------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(7,13): error FS0001: This expression was expected to have type
'Record list'
but here has type
'Record'

  • //or this:
  • doSomething {field1=0; field2=0} ;;

doSomething {field1=0; field2=0} ;;
------------^^^^^^^^^^^^^^^^^^^^

stdin(10,13): error FS1129: This expression was expected to have type 'Record list' but here an incompatible record type was given.

  • //or this:
  • doSomething {Record.field1=0; field2=0} ;;

doSomething {Record.field1=0; field2=0} ;;
------------^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(13,13): error FS1129: This expression was expected to have type 'Record list' but here an incompatible record type was given.

We see that for the first error we get a clear actionable accurate message:

stdin(77,13): error FS0001: This expression was expected to have type
Record list
but here has type
Record

But the other two entries, give a bogus error message:

stdin(13,13): error FS1129: This expression was expected to have type 'Record list' but here an incompatible record type was given.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#1283 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AADgNNYrV0y3amVaBxq7rkhnscBVWFPJks5qPRFIgaJpZM4I9k3B
.

@forki
Copy link
Contributor Author

forki commented Jun 25, 2016

a small bit of background:

the issue is that typ in https://github.com/Microsoft/visualfsharp/pull/1283/files#diff-dbb9e59b8ac1e1e04e1b00282a91ec97R2549 is given as Record list. That is because the overallTy is already resolved to this. Now the label resolution function tries to resolve the labels according to this type and sees that the type has no matching labels.

In the last bit we then see that typ is not a record type so we give a bit better error message.

In the sample with {Record.field1=0; Record.field2=0} there is one level more in the resolution process and therefor the typ for the label resolution is Record and only the later type unification is failing.

@forki
Copy link
Contributor Author

forki commented Jun 25, 2016

Ok I managed to make it a type unification error, but this change needs more review.

My strategy:

If we can't resolve to the given overallTy then we might just try to resolve to any record type and let the type checker fail directly after label resolution. I think this should work and should actually give the good error.

@forki
Copy link
Contributor Author

forki commented Jun 30, 2016

fixed

@dsyme dsyme merged commit 1e9ccfd into dotnet:master Jul 22, 2016
@forki forki deleted the record-1280 branch July 22, 2016 10:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve Error Reporting: Record does not match type when using Record Expressions

4 participants