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

Wrong location for error with polymorphic variant patterns #6330

Closed
vicuna opened this issue Feb 18, 2014 · 5 comments
Closed

Wrong location for error with polymorphic variant patterns #6330

vicuna opened this issue Feb 18, 2014 · 5 comments
Assignees

Comments

@vicuna
Copy link

vicuna commented Feb 18, 2014

Original bug ID: 6330
Reporter: @lpw25
Assigned to: @garrigue
Status: acknowledged (set by @gasche on 2014-02-23T18:02:16Z)
Resolution: open
Priority: normal
Severity: minor
Version: 4.01.0
Target version: later
Category: typing
Monitored by: @yallop @hcarty

Bug description

The following error should really be located at the second case:

   # let f (x: [< `Foo of int | `Bar of float]) = 
       match x with
        `Foo x -> x
      | `Baz -> 1
      | _ -> 0;;
   Characters 65-71:
        `Foo x -> x
        ^^^^^^
    Error: This pattern matches values of type [> `Baz | `Foo of 'a ]
           but a pattern was expected which matches values of type
           [< `Bar of float | `Foo of int ]
           The second variant type does not allow tag(s) `Baz
@vicuna
Copy link
Author

vicuna commented Feb 23, 2014

Comment author: @gasche

I did a bit of work to understand where the issue comes from -- and found out that it was not easily fixable. This will probably be obvious to Leo and Jacques, but I'll still summarize the issue in case anyone is interested.

The error location comes from the way pattern-matching of polymorphic variants are type-checked. First, the type of all the branches are unified together -- and passed through a bit of variant-pressuring magic I don't understand. Then, they are unified with the type of the pattern scrutinee. In this example, unifying both patterns together gives them both a type of the form [> `Foo of '_a | `Baz ]. When the `Foo pattern is then unified with the type [< `Foo of int | `Bar of float], you get an error (located at `Foo) about the type `Baz not being possible.

For someone like me that is not familiar with type inference of polymorphic variants, it's not obvious why it wouldn't work to first unify each branch with (an instance of) the scrutinee's type, and then unify the branch together -- a clash between one of the branch and the scrutinee would then be reported where expected. However, doing this does not work (and the implementation is very clear about the fact that the existing order is intended) on some other examples; for example,

fun x -> match (x : [< `A ]) with `A | `B -> ();;

is accepted by the current type-checking technique (with a warning about the `B being dead code), but would be rejected by trying to unify `B's type with [< `A ].

TL;DR: it's not a silly typo in the location-handling code, it's something subtle about type-checking of polymorphic variants, that is probably not going to change soon - or it needs an expert.

@github-actions
Copy link

This issue has been open one year with no activity. Consequently, it is being marked with the "stale" label. What this means is that the issue will be automatically closed in 30 days unless more comments are added or the "stale" label is removed. Comments that provide new information on the issue are especially welcome: is it still reproducible? did it appear in other contexts? how critical is it? etc.

@github-actions github-actions bot added the Stale label May 13, 2020
@garrigue
Copy link
Contributor

Update: if you write your code in the following way, you get the error at the right position.

let f (x: [`Foo of int | `Bar of float]) = match x with
          `Foo x -> x
        | `Baz -> 1
        | _ -> 0

So why doesn't it work for annotations of the form [< ...] ?
As @gasche explained, the logic used to decide whether a variant type should be closed or open requires that we do not propagate "potential presence information" to the pattern-matching typer. So this type annotation is first ignored, and then unified with each case. And we get the clash when unifying with the first case. It might be possible to make the location wider (i.e. the whole pattern-matching), but I do not see how to make it point to the second case.
Can we just decide that we won't fix this one?

@gasche
Copy link
Member

gasche commented May 13, 2020

I propose to close unless @lpw25 has a different suggestion.

@lpw25
Copy link
Contributor

lpw25 commented May 13, 2020

Seems not worth the trouble to fix

@lpw25 lpw25 closed this as completed May 13, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants