Polymorphic methods on polymorphic variants

Consider the following class:

class user =
  object (self)
    method id : 'ab. ([< `A | `B ] as 'ab) -> 'ab = fun x -> x

    method act : [ `A | `B ] -> string =
      fun x -> match self#id x with `B -> "B" | `A -> "A"
  end

Calling

(new user)#act `A

yields, surprisingly, a result of "B". However, any of the following changes cause it to yield "A" instead:

  • Changing the type of id to 'ab. 'ab -> 'ab.
  • Changing the type of id to [ `A | `B ] -> [ `A | `B ].
  • Matching (self#id x :> [ `A | `B ]) instead.
  • Changing the order of the match clauses.

In addition:

  • Calling (new user)#act `B instead also yields a return value of "B".
  • Adding a catchall case | _ -> "C" to the match (with or without changing the type of act to [> `A | `B ] -> string) changes the return value to "C".

Is something going on here that makes sense?

2 Likes

Hello,

This looks like a compiler bug. Could you please file a report at Issues · ocaml/ocaml · GitHub? Thanks!

Cheers,
Nicolas

The match is compiled to (when looking with -drawlambda):

(function self-1/101 x/102
     (let
       (self-*/100 =a self-1/101
        *match*/130 =
          (sendself self-1/101 id/94 x/102))
       "B")
)

so there is something going wrong with the pattern-matching compilation.

I can get the same issue without classes:

type r = { f : 'ab. ([< `A | `B ] as 'ab) -> 'ab; }

let id = { f = fun x -> x; }

let act : [ `A | `B ] -> string = fun x -> match id.f x with `B -> "B" | `A -> "A"

let _ = print_endline (act `A)

Okay, submitted here. Thanks; I figured it must be a bug, but wasn’t entirely sure enough of myself to submit it there right off the bat.

1 Like