


@ 187,86 +187,13 @@ let rec as_forall ty =










(*  *)










(* [equal1] groups the easy cases of the type equality test. It does not





accept arguments of the form [TyMu]. It expects a self parameter [equal]





that is used to compare the children of the two root nodes. *)










let pointwise equal tys1 tys2 =





try





List.for_all2 equal tys1 tys2





with Invalid_argument _ >





(* Catching [Invalid_argument] is bad style, but saves a couple calls





to [List.length]. A cleaner approach would be to use arrays instead





of lists. *)





false










let equal1 equal ty1 ty2 =





match ty1, ty2 with





 TyMu _, _





 _, TyMu _ >





assert false





 TyVar x1, TyVar x2 >





Int.equal x1 x2





 TyArrow (ty1a, ty1b), TyArrow (ty2a, ty2b)





 TyEq (ty1a, ty1b), TyEq (ty2a, ty2b) >





equal ty1a ty2a && equal ty1b ty2b





 TyForall ((), ty1), TyForall ((), ty2) >





equal ty1 ty2





 TyProduct tys1, TyProduct tys2 >





pointwise equal tys1 tys2





 TyConstr (Datatype.Type tyconstr1, tys1),





TyConstr (Datatype.Type tyconstr2, tys2) >





String.equal tyconstr1 tyconstr2 &&





pointwise equal tys1 tys2





 (TyVar _  TyArrow _  TyForall _  TyProduct _  TyConstr _  TyEq _),





_ >





false










(*  *)










(* An unsound approximation of the equality test. (Now unused.) *)










(* Comparing two [TyMu] types simply by comparing their bodies would be





correct, but incomplete: some types that are equal would be considered





different. *)










(* Naively unfolding every [TyMu] type is sound and complete, but leads to





potential nontermination. The following code avoids nontermination by





imposing a budget limit. This makes this equality test unsound: two types





may be considered equal when they are in fact different. *)










let rec equal budget ty1 ty2 =





match ty1, ty2 with





 (TyMu _ as ty1), ty2





 ty2, (TyMu _ as ty1) >





budget = 0  equal (budget  1) (unfold ty1) ty2





 _, _ >





equal1 (equal budget) ty1 ty2










let budget =





4










let _unsound_equal ty1 ty2 =





equal budget ty1 ty2










(*  *)










(* A sound approximation of the equality test. *)










(* The System F types produced by an ML type inference algorithm cannot





contain [TyForall] under [TyMu]. In this restricted setting, deciding





type equality is relatively easy. We proceed in two layers, as follows:










 Initially, we perform a normal (structural) equality test, going





down under [TyForall] constructors if necessary. As soon as we





hit a [TyMu] constructor on either side, we switch to the lower





layer:










 In the lower layer, we know that we cannot hit a [TyForall]





constructor (if we do, we report that the types differ). We





map each type (separately) to a graph of unification variables





(where every variable has rigid structure), then we check that





the two graphs can be unified. *)





type equality is relatively easy. We map each type to a graph of





unification variables (where every variable has rigid structure),





then we check that the two graphs can be unified. *)










exception Clash =





Structure.Iter2




