Add missing lower_contravariant call (fixes #9856)#9857
Add missing lower_contravariant call (fixes #9856)#9857Octachron merged 3 commits intoocaml:4.11from
lower_contravariant call (fixes #9856)#9857Conversation
|
I don't think we are in a rush to merge overnight, so maybe we could have the regression tests in the PR, and include similar-looking potential-regressions (with polymorphic methods or local type constructors)? |
|
We need a proper review before integrating the fix in panic mode. This means that there is probably time to write some regression tests in parallel. |
|
The regression tests are not left out to save time, but to (very slightly) decrease the chance that this patch introduces new problems. If people prefer I can add the test on this branch but in general I think it is better for a bugfix release to include the bugfix and nothing more. |
|
I wise man wrote somewhere that the issue fixed by this PR could have beeen
Let's write those tests! |
|
Yes, I agree with @gasche here and also think it would be nice to have
the tests within the PR.
|
garrigue
left a comment
There was a problem hiding this comment.
I agree that this call to lower_contravariant was done in 4.10 inside check_univars and apparently removed in 4.11, so this seems to be a correct fix.
I also would like to see a regression test.
fc0268c to
203ef1f
Compare
|
I've moved the regression test to this PR and added a Changes entry |
| ^^^^^^^^ | ||
| Error: This field value has type 'b option ref which is less general than | ||
| 'a. 'a option ref | ||
| |}] |
There was a problem hiding this comment.
Currently the regression test checks type a . a option ref, which is unsoundly accepted in trunk, and { foo : 'a . 'a option ref }, which is correctly rejected. I would be in favor of adding two other tests to cover different forms of explicit polymorphism:
let test : 'a . 'a list ref = ref []
(* unsound in trunk *)
let test (type a) : a list ref = ref []
(* accepted in trunk, with a weak polymorphic type, which I find surprising *)(Note: arguably type a . a list ref is a combination of both those features, but I prefer to (also) test the simpler forms. I didn't expect that the (type a) version would type-check, for example.)
There was a problem hiding this comment.
Locally abstract types are quite orthogonal to explicit polymorphism, and thus these two tests seem quite redundant too me?
There was a problem hiding this comment.
I had the impression that the use of a locally abstract type would guarantee that the definition would be (strongly) polymorphic under the corresponding type variable, so clearly the two features are not orthogonal to me. I have no idea whether it was just me thinking this, or whether this is a wide-spread assumption.
I think that my impression partly comes from the similarity between let t (type a) .. and the System F syntax for abstraction over a type variable. I read this code as if a was a name for a type (treated abstractly in the definition) that can be chosen by each user of t, sort of like a lightweight functor notation. With this interpretation the currently-accepted behavior let foo (type a) : a list ref = [] is wrong.
(Another way to object to this behavior is to say that a weak type variable is scoped outside the declaration that contains it, so unifying it with a locally abstract type could be treated as an escape of that local type.)
I just checked, and the documentation does not say that (type a) will be replaced by a a generalizable type variable, just a type variable, so the documentation is not contradicted by this example. I still find it surprising. (But this is orthogonal to the present bug.)
There was a problem hiding this comment.
Actually, the paragraph Polymorphic syntax is quite explicit about this behavior:
The
(type typeconstr-name)syntax construction by itself does not make polymorphic the type variable it introduces, but it can be combined with explicit polymorphic annotations where needed.
|
Would it make sense to add a comment on Looking at the code, this PR fixes the only call site where this precondition was broken. |
|
This function is not unique on this front: basically anything called generalize has that property. I'm in favour of more documentation in the type checker, but I don't think these kind of ad-hoc comments really help. This bug didn't come from not knowing that the function needed to be called but from thinking that it already had been. |
#1132 accidentally removed a call to
lower_contravariant, presumably because of thelower_contravariantcall a few lines up which looks equivalent but isn't. This adds it back.This is a minimal PR for fixing the bug on the 4.11 branch. We should also add a regression test etc. for the patch to trunk.