comparison src/elaborate.sml @ 172:021f5beb6f8d

Pattern match coverage checking
author Adam Chlipala <adamc@hcoop.net>
date Thu, 31 Jul 2008 10:31:30 -0400
parents c7a6e6dbc318
children 8221b95cc24c
comparison
equal deleted inserted replaced
171:c7a6e6dbc318 172:021f5beb6f8d
35 structure D = Disjoint 35 structure D = Disjoint
36 36
37 open Print 37 open Print
38 open ElabPrint 38 open ElabPrint
39 39
40 structure IM = IntBinaryMap
40 structure SS = BinarySetFn(struct 41 structure SS = BinarySetFn(struct
41 type ord_key = string 42 type ord_key = string
42 val compare = String.compare 43 val compare = String.compare
43 end) 44 end)
44 45
812 | DuplicatePatternVariable of ErrorMsg.span * string 813 | DuplicatePatternVariable of ErrorMsg.span * string
813 | PatUnify of L'.pat * L'.con * L'.con * cunify_error 814 | PatUnify of L'.pat * L'.con * L'.con * cunify_error
814 | UnboundConstructor of ErrorMsg.span * string 815 | UnboundConstructor of ErrorMsg.span * string
815 | PatHasArg of ErrorMsg.span 816 | PatHasArg of ErrorMsg.span
816 | PatHasNoArg of ErrorMsg.span 817 | PatHasNoArg of ErrorMsg.span
818 | Inexhaustive of ErrorMsg.span
817 819
818 fun expError env err = 820 fun expError env err =
819 case err of 821 case err of
820 UnboundExp (loc, s) => 822 UnboundExp (loc, s) =>
821 ErrorMsg.errorAt loc ("Unbound expression variable " ^ s) 823 ErrorMsg.errorAt loc ("Unbound expression variable " ^ s)
850 ErrorMsg.errorAt loc ("Unbound constructor " ^ s ^ " in pattern") 852 ErrorMsg.errorAt loc ("Unbound constructor " ^ s ^ " in pattern")
851 | PatHasArg loc => 853 | PatHasArg loc =>
852 ErrorMsg.errorAt loc "Constructor expects no argument but is used with argument" 854 ErrorMsg.errorAt loc "Constructor expects no argument but is used with argument"
853 | PatHasNoArg loc => 855 | PatHasNoArg loc =>
854 ErrorMsg.errorAt loc "Constructor expects argument but is used with no argument" 856 ErrorMsg.errorAt loc "Constructor expects argument but is used with no argument"
857 | Inexhaustive loc =>
858 ErrorMsg.errorAt loc "Inexhaustive 'case'"
855 859
856 fun checkCon (env, denv) e c1 c2 = 860 fun checkCon (env, denv) e c1 c2 =
857 unifyCons (env, denv) c1 c2 861 unifyCons (env, denv) c1 c2
858 handle CUnify (c1, c2, err) => 862 handle CUnify (c1, c2, err) =>
859 (expError env (Unify (e, c1, c2, err)); 863 (expError env (Unify (e, c1, c2, err));
996 (case E.lookupConstructor env x of 1000 (case E.lookupConstructor env x of
997 NONE => (expError env (UnboundConstructor (loc, x)); 1001 NONE => (expError env (UnboundConstructor (loc, x));
998 rerror) 1002 rerror)
999 | SOME (n, to, dn) => pcon (L'.PConVar n, po, to, dn)) 1003 | SOME (n, to, dn) => pcon (L'.PConVar n, po, to, dn))
1000 | L.PCon _ => raise Fail "uhoh" 1004 | L.PCon _ => raise Fail "uhoh"
1005 end
1006
1007 datatype coverage =
1008 Wild
1009 | Datatype of coverage IM.map
1010
1011 fun exhaustive (env, denv, t, ps) =
1012 let
1013 fun pcCoverage pc =
1014 case pc of
1015 L'.PConVar n => n
1016 | _ => raise Fail "uh oh^2"
1017
1018 fun coverage (p, _) =
1019 case p of
1020 L'.PWild => Wild
1021 | L'.PVar _ => Wild
1022 | L'.PCon (pc, NONE) => Datatype (IM.insert (IM.empty, pcCoverage pc, Wild))
1023 | L'.PCon (pc, SOME p) => Datatype (IM.insert (IM.empty, pcCoverage pc, coverage p))
1024
1025 fun merge (c1, c2) =
1026 case (c1, c2) of
1027 (Wild, _) => Wild
1028 | (_, Wild) => Wild
1029
1030 | (Datatype cm1, Datatype cm2) => Datatype (IM.unionWith merge (cm1, cm2))
1031
1032 fun combinedCoverage ps =
1033 case ps of
1034 [] => raise Fail "Empty pattern list for coverage checking"
1035 | [p] => coverage p
1036 | p :: ps => merge (coverage p, combinedCoverage ps)
1037
1038 fun isTotal (c, t) =
1039 case c of
1040 Wild => (true, nil)
1041 | Datatype cm =>
1042 let
1043 val ((t, _), gs) = hnormCon (env, denv) t
1044 in
1045 case t of
1046 L'.CNamed n =>
1047 let
1048 val dt = E.lookupDatatype env n
1049 val cons = E.constructors dt
1050 in
1051 foldl (fn ((_, n, to), (total, gs)) =>
1052 case IM.find (cm, n) of
1053 NONE => (false, gs)
1054 | SOME c' =>
1055 case to of
1056 NONE => (total, gs)
1057 | SOME t' =>
1058 let
1059 val (total, gs') = isTotal (c', t')
1060 in
1061 (total, gs' @ gs)
1062 end)
1063 (true, gs) cons
1064 end
1065 | L'.CError => (true, gs)
1066 | _ => raise Fail "isTotal: Not a datatype"
1067 end
1068 in
1069 isTotal (combinedCoverage ps, t)
1001 end 1070 end
1002 1071
1003 fun elabExp (env, denv) (eAll as (e, loc)) = 1072 fun elabExp (env, denv) (eAll as (e, loc)) =
1004 let 1073 let
1005 1074
1225 val gs3 = checkCon (env, denv) e' et result 1294 val gs3 = checkCon (env, denv) e' et result
1226 in 1295 in
1227 ((p', e'), gs1 @ gs2 @ gs3 @ gs) 1296 ((p', e'), gs1 @ gs2 @ gs3 @ gs)
1228 end) 1297 end)
1229 gs1 pes 1298 gs1 pes
1299
1300 val (total, gs') = exhaustive (env, denv, et, map #1 pes')
1230 in 1301 in
1231 ((L'.ECase (e', pes', result), loc), result, gs) 1302 if total then
1303 ()
1304 else
1305 expError env (Inexhaustive loc);
1306
1307 ((L'.ECase (e', pes', result), loc), result, gs' @ gs)
1232 end 1308 end
1233 end 1309 end
1234 1310
1235 1311
1236 datatype decl_error = 1312 datatype decl_error =