Fix code duplication in pattern matching of polymorphic variants#11893
Fix code duplication in pattern matching of polymorphic variants#11893lthls merged 7 commits intoocaml:trunkfrom
Conversation
|
We should ask @maranget for the change in switch strategy. @maranget: Vincent is asking about the changes in |
|
@lthls your "second attempt" commit contains a revert of the first that is mixed with other things, I find this a bit confusing. |
|
I think that we need @maranget to look at this patch anyway. I am surprised by the proposed fix, because there is already code in matching.ml to distinguish shared and non-shared action, for example Lines 2227 to 2239 in 4d932a8 The fix seems redundant with this existing logic, so I think that are missing something. |
|
Here is a more detailed trace of what is going on:
My patch was written on |
|
Thanks! These walkthrough are very useful.
So I guess here is an answer to my comment above: it is in fact not true that variants are very sparse. The hashing function is "bad" enough that we do get dense clusters so using the switcher is worth it. |
|
I have reviewed the patch and it looks fine to me. As regards @gasche's question:
Frankly, I do not remember and have no idea. Indeed it looks a good idea to call the switcher in all situations. However, if it ain't broken, don't fix it... |
|
@maranget could you "approve" the PR if you like the patch? ("Files changed" tab in the top right > "review changes" button in the top right > "Approve".) |
|
@lthls I have one request before merging this: please have a comment to the code that explicitly points to this issue / the bug report, to explain why there is this handling here. Without your trace above I don't think that anyone could easily reverse-engineer why it is necessary. |
|
I've tried to create another similar example that uses GADTs instead of polymorphic variants: type keep = private Keep
type drop = private Drop
type _ t =
| C00 : keep t
| C01 : drop t
| C02 : drop t
| C03 : drop t
| C04 : drop t
| C05 : drop t
| C06 : drop t
| C07 : drop t
| C08 : drop t
| C09 : drop t
| C10 : drop t
| C11 : drop t
| C12 : drop t
| C13 : drop t
| C14 : drop t
| C15 : drop t
| C16 : drop t
| C17 : drop t
| C18 : drop t
| C19 : drop t
| C20 : keep t
| C21 : drop t
| C22 : drop t
| C23 : drop t
| C24 : keep t
| C25 : keep t
| C26 : drop t
| C27 : drop t
| C28 : keep t
let not_at_toplevel b =
let f (x: keep t) =
match x with
| C00 ->
begin
let[@local] handler x = x + 1 in
if b then handler 0 else handler 1
end
| C20 ->
begin
let[@local] handler x = x + 2 in
if b then handler 0 else handler 1
end
| C24 ->
begin
let[@local] handler x = x + 3 in
if b then handler 0 else handler 1
end
| C25 ->
begin
let[@local] handler x = x + 4 in
if b then handler 0 else handler 1
end
| C28 ->
begin
let[@local] handler x = x + 5 in
if b then handler 0 else handler 1
end
in
fIt doesn't trigger the exact same bug (the local optimisation is done after pattern-matching). Instead, it triggers another issue (a continuation used without a handler), which will crash the compiler even without |
|
So the problem is that |
|
Do I correctly understand that we would have detected the problem more easily if the calls to Hashtbl.add in Lines 291 to 307 in 6b96b73 were preceded by an |
|
(We could also be more careful in the |
|
My preference would be to have a |
|
Fair enough. |
Fixes #11887.
I've left in the first commit a different approach, that always uses test sequences instead of switches for polymorphic variants. If all variant constructors are constant, we already force the use of test sequences, although I don't know why this case is special (the difference was introduced in 157c4e5; before that we used test sequences in all cases). So it looked like a simple and reasonable fix to revert to test sequences only in all those cases.
However, I think that with enough care we could create the same problem with regular variants (with lots of constructors), so I went with what I think is the right fix, which is to detect potential duplication in
Matching.SArg.make_switchand introduce wrappers.I think we could now remove the special case in
Matching.as_interval_nofailthat detects holes and shares the first action in this case, but I haven't done it here (and I haven't checked that it works).