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

Univars can escape through polymorphic variants #6744

Open
vicuna opened this issue Jan 6, 2015 · 5 comments

Comments

Projects
None yet
3 participants
@vicuna
Copy link

commented Jan 6, 2015

Original bug ID: 6744
Reporter: @lpw25
Assigned to: @garrigue
Status: assigned (set by @garrigue on 2015-01-16T15:37:54Z)
Resolution: open
Priority: normal
Severity: minor
Target version: later
Category: typing
Related to: #7741

Bug description

When a unifying closed polymorphic variant types (e.g. [< `Foo of int]) there is no equivalent of the occur_univars check. This can allow univars to escape, for example:

# let (n : < m : 'a. [< `Foo of int] -> 'a >) = 
     object method m : 'x. [< `Foo of 'x] -> 'x = fun x -> assert false end;;
  Characters -1--1:
  let (n : < m : 'a. [< `Foo of int] -> 'a >) = 

Error: Values do not match:
         val n : < m : 'a. [< `Foo of int & 'a0 ] -> 'a >
       is not included in
         val n : < m : 'a. [< `Foo of int & 'a0 ] -> 'a >

In this example, the escaped univar doesn't get very far because it triggers an module inclusion error of the n value with itself, and I have not been able to produce an example of genuine unsoundness because of this bug. However, it is clearly not correct to allow the variable to escape like this, and could potentially be unsound.

File attachments

@vicuna

This comment has been minimized.

Copy link
Author

commented Jan 6, 2015

Comment author: @lpw25

In fact, unification of closed polymorphic variants containing univars behaves strangely even without an escaping univar:

  # let n = 
       object method m : 'x. [< `Foo of 'x] -> 'x = fun x -> assert false end;;
    val n : < m : 'x. [< `Foo of 'x ] -> 'x > = <obj>

  # let m : < m : 'x. [< `Foo of 'x ] -> 'x > = n;;
  Characters 44-45:
    let m : < m : 'x. [< `Foo of 'x ] -> 'x > = n;;
                                                ^
  Error: This expression has type < m : 'x. [< `Foo of 'x & 'x0 ] -> 'x >
         but an expression was expected of type 'a
         The universal variable 'x0 would escape its scope
@vicuna

This comment has been minimized.

Copy link
Author

commented Jan 6, 2015

Comment author: @lpw25

Here's a slightly clearer example of a univar escaping:

# let (n : 'b -> < m : 'a . ([< `Foo of int] as 'b) -> 'a >) = 
     fun x -> object method m : 'x. [< `Foo of 'x] -> 'x = fun x -> assert false end;;
  Characters -1--1:
  let (n : 'b -> < m : 'a . ([< `Foo of int] as 'b) -> 'a >) = 

Error: Values do not match:
         val n : ([< `Foo of int & 'a ] as 'b) -> < m : 'a0. 'b -> 'a0 >
       is not included in
         val n : ([< `Foo of int & 'a ] as 'b) -> < m : 'a0. 'b -> 'a0 >

Note the & 'a in the argument type. That is the univar from 'a . ([< Foo of int] as 'b) -> 'a`.

@vicuna

This comment has been minimized.

Copy link
Author

commented Jan 16, 2015

Comment author: @garrigue

Thanks for the report.
Here is a patch that solves partly the problem.
However, for some reason the behavior is not the same in normal and principal mode.

I'm not 100% sure which is right: in theory, all your examples should be rejected, because a universal variable cannot appear inside a non-quantified flexible variant type. I.e., what you really want to write (and is accepted) is:
let n = object
method m : 'x 'o. ([< `Foo of 'x] as 'o) -> 'x = fun x -> assert false
end;;

Yet, in practice ocaml tries to do more than that, by allowing "known fields" to contain universal variables. I.e., the implementation uses row variables rather than kinded variables, so that these fields are not seen as being "under" the row variable, but rather as "siblings". This works as expected in normal mode, but , there are some problems in principal mode. Maybe it is better to follow the theory...

@vicuna

This comment has been minimized.

Copy link
Author

commented Jan 17, 2015

Comment author: @garrigue

Committed the patch in trunk, at revision 15780.
Leave the PR open, as the principal mode case should be improved.

@yallop

This comment has been minimized.

Copy link
Member

commented Apr 8, 2019

@lpw25, @garrigue: can this be closed? The examples above all seem to behave correctly now -- i.e. they are accepted or trigger a clear diagnostic "The universal variable 'x would escape its scope" as appropriate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.