diff src/elab_env.sml @ 750:059074c8d2fc

LEFT JOIN
author Adam Chlipala <adamc@hcoop.net>
date Tue, 28 Apr 2009 11:05:28 -0400
parents 9864b64b1700
children d484df4e841a
line wrap: on
line diff
--- a/src/elab_env.sml	Tue Apr 28 10:11:56 2009 -0400
+++ b/src/elab_env.sml	Tue Apr 28 11:05:28 2009 -0400
@@ -507,6 +507,8 @@
                 (CUnif (_, _, _, ref (SOME c1)), _) => unify d (c1, c2)
               | (_, CUnif (_, _, _, ref (SOME c2))) => unify d (c1, c2)
 
+              | (CUnif _, _) => ()
+
               | (c1', CRel n2) =>
                 if n2 < d then
                     case c1' of
@@ -587,7 +589,56 @@
                         | (d, _) => d}
                0
 
-fun resolveClass (env : env) =
+fun postUnify x =
+    let
+        fun unify (c1, c2) =
+            case (#1 c1, #1 c2) of
+                (CUnif (_, _, _, ref (SOME c1)), _) => unify (c1, c2)
+              | (_, CUnif (_, _, _, ref (SOME c2))) => unify (c1, c2)
+
+              | (CUnif (_, _, _, r), _) => r := SOME c2
+
+              | (TFun (d1, r1), TFun (d2, r2)) => (unify (d1, d2); unify (r1, r2))
+              | (TCFun (_, _, k1, r1), TCFun (_, _, k2, r2)) => (unifyKinds (k1, k2); unify (r1, r2))
+              | (TRecord c1, TRecord c2) => unify (c1, c2)
+              | (TDisjoint (a1, b1, c1), TDisjoint (a2, b2, c2)) =>
+                (unify (a1, a2); unify (b1, b2); unify (c1, c2))
+
+              | (CRel n1, CRel n2) => if n1 = n2 then () else raise Unify
+              | (CNamed n1, CNamed n2) => if n1 = n2 then () else raise Unify
+              | (CModProj (n1, ms1, x1), CModProj (n2, ms2, x2)) =>
+                if n1 = n2 andalso ms1 = ms2 andalso x1 = x2 then () else raise Unify
+              | (CApp (f1, x1), CApp (f2, x2)) => (unify (f1, f2); unify (x1, x2))
+              | (CAbs (_, k1, b1), CAbs (_, k2, b2)) => (unifyKinds (k1, k2); unify (b1, b2))
+
+              | (CKAbs (_, b1), CKAbs (_, b2)) => unify (b1, b2)
+              | (CKApp (c1, k1), CKApp (c2, k2)) => (unify (c1, c2); unifyKinds (k1, k2))
+              | (TKFun (_, c1), TKFun (_, c2)) => unify (c1, c2)
+
+              | (CName s1, CName s2) => if s1 = s2 then () else raise Unify
+
+              | (CRecord (k1, xcs1), CRecord (k2, xcs2)) =>
+                (unifyKinds (k1, k2);
+                 ListPair.appEq (fn ((x1, c1), (x2, c2)) => (unify (x1, x2); unify (c1, c2))) (xcs1, xcs2)
+                 handle ListPair.UnequalLengths => raise Unify)
+              | (CConcat (f1, x1), CConcat (f2, x2)) => (unify (f1, f2); unify (x1, x2))
+              | (CMap (d1, r1), CMap (d2, r2)) => (unifyKinds (d1, d2); unifyKinds (r1, r2))
+
+              | (CUnit, CUnit) => ()
+
+              | (CTuple cs1, CTuple cs2) => (ListPair.appEq unify (cs1, cs2)
+                                             handle ListPair.UnequalLengths => raise Unify)
+              | (CProj (c1, n1), CProj (c2, n2)) => (unify (c1, c2);
+                                                     if n1 = n2 then () else raise Unify)
+
+              | _ => raise Unify
+    in
+        unify x
+    end
+
+fun postUnifies x = (postUnify x; true) handle Unify => false
+
+fun resolveClass (hnorm : con -> con) (env : env) =
     let
         fun resolve c =
             let
@@ -608,7 +659,8 @@
                                         let
                                             val eos = map (resolve o unifySubst rs) cs
                                         in
-                                            if List.exists (not o Option.isSome) eos then
+                                            if List.exists (not o Option.isSome) eos
+                                               orelse not (postUnifies (c, unifySubst rs c')) then
                                                 tryRules rules'
                                             else
                                                 let
@@ -634,9 +686,34 @@
                             tryGrounds (#ground class)
                         end
             in
-                case class_head_in c of
-                    SOME f => doHead f
-                  | _ => NONE
+                case #1 c of
+                    TRecord c =>
+                    (case #1 (hnorm c) of
+                         CRecord (_, xts) =>
+                         let
+                             fun resolver (xts, acc) =
+                                 case xts of
+                                     [] => SOME (ERecord acc, #2 c)
+                                   | (x, t) :: xts =>
+                                     let
+                                         val t = hnorm t
+
+                                         val t = case t of
+                                                     (CApp (f, x), loc) => (CApp (hnorm f, hnorm x), loc)
+                                                   | _ => t
+                                     in
+                                         case resolve t of
+                                             NONE => NONE
+                                           | SOME e => resolver (xts, (x, e, t) :: acc)
+                                     end
+                         in
+                             resolver (xts, [])
+                         end
+                       | _ => NONE)
+                  | _ =>
+                    case class_head_in c of
+                        SOME f => doHead f
+                      | _ => NONE
             end
     in
         resolve