Skip to content

Unsoundness involving non-injective types + gadts #13579

@v-gb

Description

@v-gb

The following program is wrongly accepted by the typechecker, which can be turned into a segfault:

module F(X : sig type 'a t end) = struct
  type (_, _) gadt = T : ('a X.t, 'a) gadt
  
  (*
    let __ (type a b) (Equal : (a X.t, b X.t) Type.eq) =
      (Equal : (a, b) Type.eq)
   *)

  let equate_param2_based_on_param1 (type tt m1 m2)
        (T : (tt, m1) gadt) (T : (tt, m2) gadt) : (m1, m2) Type.eq =
     Equal
  ;;
end

module Z = F(struct type 'a t = unit end)

let () =
  let t1 = (Z.T : (unit, int) Z.gadt) in
  let t2 = (Z.T : (unit, string) Z.gadt) in
  let eq : (int, string) Type.eq = Z.equate_param2_based_on_param1 t1 t2 in
  let cast (type a b) (Equal : (a, b) Type.eq) (a : a) : b = a in
  print_string (cast eq 1)
;;

The problem is that the function equate_param2_based_on_param1 is considered well-typed by the typechecker, but in reality it's well-typed iff X.t is injective in 'a. By contrast, the commented-out injectivity function is correctly accepted iff X.t is injective in 'a.

(this came up while @mbarbin and I were thinking about the type safety in https://github.com/mbarbin/provider/).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions