Import Debian changes 20180207-1
[hcoop/debian/mlton.git] / mlton / xml / type-check.fun
CommitLineData
7f918cf1
CE
1(* Copyright (C) 1999-2007 Henry Cejtin, Matthew Fluet, Suresh
2 * Jagannathan, and Stephen Weeks.
3 * Copyright (C) 1997-2000 NEC Research Institute.
4 *
5 * MLton is released under a BSD-style license.
6 * See the file MLton-LICENSE for details.
7 *)
8
9functor TypeCheck (S: TYPE_CHECK_STRUCTS): TYPE_CHECK =
10struct
11
12open S
13open Dec PrimExp
14
15fun typeCheck (program as Program.T {datatypes, body, overflow}): unit =
16 let
17 (* tyvarInScope is used to ensure that tyvars never shadow themselves. *)
18 val {get = tyvarInScope: Tyvar.t -> bool ref, ...} =
19 Property.get (Tyvar.plist,
20 Property.initFun (fn _ => ref false))
21 fun bindTyvars (vs: Tyvar.t vector): unit =
22 Vector.foreach (vs, fn v =>
23 let
24 val r = tyvarInScope v
25 in
26 if !r
27 then Type.error ("tyvar already in scope",
28 Tyvar.layout v)
29 else r := true
30 end)
31 fun unbindTyvars (vs: Tyvar.t vector): unit =
32 Vector.foreach (vs, fn v => tyvarInScope v := false)
33 (* checkType makes sure all tyvars are bound. *)
34 fun checkType (ty: Type.t): unit =
35 Type.hom {ty = ty,
36 con = fn _ => (),
37 var = fn a => if !(tyvarInScope a)
38 then ()
39 else Type.error ("tyvar not in scope",
40 Tyvar.layout a)}
41 fun checkTypes v = Vector.foreach (v, checkType)
42 val {get = getCon: Con.t -> {tyvars: Tyvar.t vector, ty: Type.t},
43 set, ...} =
44 Property.getSetOnce (Con.plist,
45 Property.initRaise ("scheme", Con.layout))
46 fun setCon ({con, arg}, tyvars, result: Type.t): unit =
47 (checkType result
48 ; set (con, {tyvars = tyvars,
49 ty = (case arg of
50 NONE => result
51 | SOME ty => (checkType ty
52 ; Type.arrow (ty, result)))}))
53 fun checkConExp (c: Con.t, ts: Type.t vector): Type.t =
54 let
55 val _ = checkTypes ts
56 val {tyvars, ty} = getCon c
57 in
58 Type.substitute (ty, Vector.zip (tyvars, ts))
59 end
60 val {get = getVar: Var.t -> {tyvars: Tyvar.t vector, ty: Type.t},
61 set = setVar, ...} =
62 Property.getSet (Var.plist,
63 Property.initRaise ("var scheme", Var.layout))
64 val getVar =
65 Trace.trace
66 ("Xml.TypeCheck.getVar", Var.layout, fn {tyvars, ty} =>
67 Layout.record [("tyvars", Vector.layout Tyvar.layout tyvars),
68 ("ty", Type.layout ty)])
69 getVar
70 val setVar =
71 Trace.trace2
72 ("Xml.TypeCheck.setVar", Var.layout, fn {tyvars, ty} =>
73 Layout.record [("tyvars", Vector.layout Tyvar.layout tyvars),
74 ("ty", Type.layout ty)],
75 Layout.ignore)
76 setVar
77 fun checkVarExp (VarExp.T {var, targs}): Type.t =
78 let
79 val _ = checkTypes targs
80 val {tyvars, ty} = getVar var
81 in if Vector.length targs = Vector.length tyvars
82 then Type.substitute (ty, Vector.zip (tyvars, targs))
83 else
84 Type.error ("variable applied to wrong number of type args",
85 let open Layout
86 in align [Var.layout var,
87 seq [str "tyvars: ",
88 Vector.layout Tyvar.layout tyvars],
89 seq [str "targs: ",
90 Vector.layout Type.layout targs]]
91 end)
92 end
93 fun checkVarExps xs = Vector.map (xs, checkVarExp)
94 fun checkPat (p as Pat.T {con, targs, arg}): Type.t =
95 let
96 val t = checkConExp (con, targs)
97 in
98 case (arg, Type.deArrowOpt t) of
99 (NONE, NONE) => t
100 | (SOME (x, ty), SOME (t1, t2)) =>
101 (checkType ty
102 ; if Type.equals (t1, ty)
103 then (setVar (x, {tyvars = Vector.new0 (),
104 ty = t1}) ; t2)
105 else (Type.error
106 ("argument constraint of wrong type",
107 let open Layout
108 in align [seq [str "constructor expects : ", Type.layout t1],
109 seq [str "but got: ", Type.layout ty],
110 seq [str "p: ", Pat.layout p]]
111 end)))
112 | _ => Type.error ("constructor pattern mismatch", Pat.layout p)
113 end
114 val traceCheckExp =
115 Trace.trace
116 ("Xml.TypeCheck.checkExp", Exp.layout, Type.layout)
117 val traceCheckPrimExp =
118 Trace.trace2
119 ("Xml.TypeCheck.checkPrimExp", PrimExp.layout, Type.layout, Type.layout)
120 val traceCheckLambda =
121 Trace.trace
122 ("Xml.TypeCheck.checkLambda", Lambda.layout, Type.layout)
123 val traceCheckDec =
124 Trace.trace
125 ("Xml.TypeCheck.checkDec", Dec.layout, Unit.layout)
126 local
127 val exnType = ref NONE
128 in
129 fun isExnType t =
130 case !exnType of
131 NONE => (exnType := SOME t; true)
132 | SOME t' => Type.equals (t, t')
133 end
134 fun check (t: Type.t, t': Type.t, layout: unit -> Layout.t): unit =
135 if Type.equals (t, t')
136 then ()
137 else Type.error ("type mismatch",
138 Layout.align [Type.layout t,
139 Type.layout t',
140 layout ()])
141 fun checkExp arg: Type.t =
142 traceCheckExp
143 (fn (exp: Exp.t) =>
144 let val {decs, result} = Exp.dest exp
145 in List.foreach (decs, checkDec)
146 ; checkVarExp result
147 end) arg
148 and checkPrimExp arg: Type.t =
149 traceCheckPrimExp
150 (fn (e: PrimExp.t, ty: Type.t) =>
151 let
152 fun error msg =
153 Type.error (msg, let open Layout
154 in seq [str "exp: ", PrimExp.layout e]
155 end)
156 fun checkApp (t1, x) =
157 let
158 val t2 = checkVarExp x
159 in
160 case Type.deArrowOpt t1 of
161 NONE => error "function not of arrow type"
162 | SOME (t2', t3) =>
163 if Type.equals (t2, t2') then t3
164 else
165 Type.error
166 ("actual and formal not of same type",
167 let open Layout
168 in align [seq [str "actual: ", Type.layout t2],
169 seq [str "formal: ", Type.layout t2'],
170 seq [str "expression: ",
171 PrimExp.layout e]]
172 end)
173 end
174 in
175 case e of
176 App {arg, func} => checkApp (checkVarExp func, arg)
177 | Case {cases, default, test} =>
178 let
179 val default = Option.map (default, checkExp o #1)
180 fun equalss v =
181 if Vector.isEmpty v
182 then Error.bug "Xml.TypeCheck.equalss"
183 else
184 let
185 val t = Vector.first v
186 in
187 if Vector.forall (v, fn t' => Type.equals (t, t'))
188 then SOME t
189 else NONE
190 end
191 fun finish (ptys: Type.t vector,
192 etys: Type.t vector): Type.t =
193 case (equalss ptys, equalss etys) of
194 (NONE, _) => error "patterns not of same type"
195 | (_, NONE) => error "branches not of same type"
196 | (SOME pty, SOME ety) =>
197 if Type.equals (checkVarExp test, pty)
198 then
199 case default of
200 NONE => ety
201 | SOME t =>
202 if Type.equals (ety, t)
203 then ety
204 else error "default of wrong type"
205 else error "test and patterns of different types"
206 datatype z = datatype Cases.t
207 in
208 case cases of
209 Con cases =>
210 finish (Vector.unzip
211 (Vector.map (cases, fn (p, e) =>
212 (checkPat p, checkExp e))))
213 | Word (s, cs) =>
214 finish (Vector.new1 (Type.word s),
215 Vector.map (cs, fn (_, e) => checkExp e))
216 end
217 | ConApp {con, targs, arg} =>
218 let
219 val t = checkConExp (con, targs)
220 in
221 case arg of
222 NONE => t
223 | SOME e => checkApp (t, e)
224 end
225 | Const c => Type.ofConst c
226 | Handle {try, catch = (catch, catchType), handler, ...} =>
227 let
228 val _ = if isExnType catchType
229 then ()
230 else error "handle with non-exn type for catch"
231 val ty = checkExp try
232 val _ = setVar (catch, {tyvars = Vector.new0 (),
233 ty = catchType})
234 val ty' = checkExp handler
235 in
236 if Type.equals (ty, ty')
237 then ty
238 else error "bad handle"
239 end
240 | Lambda l => checkLambda l
241 | PrimApp {args, prim, targs} =>
242 let
243 val _ = checkTypes targs
244 val () =
245 if Type.checkPrimApp {args = checkVarExps args,
246 prim = prim,
247 result = ty,
248 targs = targs}
249 then ()
250 else error "bad primapp"
251 in
252 ty
253 end
254 | Profile _ => Type.unit
255 | Raise {exn, ...} =>
256 if isExnType (checkVarExp exn)
257 then ty
258 else error "bad raise"
259 | Select {tuple, offset} =>
260 (case Type.deTupleOpt (checkVarExp tuple) of
261 NONE => error "selection from nontuple"
262 | SOME ts => Vector.sub (ts, offset))
263 | Tuple xs =>
264 if 1 = Vector.length xs
265 then error "unary tuple"
266 else Type.tuple (checkVarExps xs)
267 | Var x => checkVarExp x
268 end) arg
269 and checkLambda arg: Type.t =
270 traceCheckLambda
271 (fn (l: Lambda.t) =>
272 let
273 val {arg, argType, body, ...} = Lambda.dest l
274 val _ = checkType argType
275 val _ = setVar (arg, {tyvars = Vector.new0 (), ty = argType})
276 in
277 Type.arrow (argType, checkExp body)
278 end) arg
279 and checkDec arg: unit =
280 traceCheckDec
281 (fn (d: Dec.t) =>
282 let
283 val check = fn (t, t') => check (t, t', fn () => Dec.layout d)
284 in
285 case d of
286 Exception c => setCon (c, Vector.new0 (), Type.exn)
287 | Fun {tyvars, decs} =>
288 (bindTyvars tyvars
289 ; (Vector.foreach
290 (decs, fn {ty, var, ...} =>
291 (checkType ty
292 ; setVar (var, {tyvars = tyvars, ty = ty}))))
293 ; Vector.foreach (decs, fn {ty, lambda, ...} =>
294 check (ty, checkLambda lambda))
295 ; unbindTyvars tyvars)
296 | MonoVal {var, ty, exp} =>
297 (checkType ty
298 ; check (ty, checkPrimExp (exp, ty))
299 ; setVar (var, {tyvars = Vector.new0 (), ty = ty}))
300 | PolyVal {tyvars, var, ty, exp} =>
301 (bindTyvars tyvars
302 ; checkType ty
303 ; check (ty, checkExp exp)
304 ; unbindTyvars tyvars
305 ; setVar (var, {tyvars = tyvars, ty = ty}))
306 end) arg
307 val _ =
308 Vector.foreach
309 (datatypes, fn {tycon, tyvars, cons} =>
310 let
311 val _ = bindTyvars tyvars
312 val ty = Type.con (tycon, Vector.map (tyvars, Type.var))
313 val _ = Vector.foreach (cons, fn c => setCon (c, tyvars, ty))
314 val _ = unbindTyvars tyvars
315 in
316 ()
317 end)
318 val _ =
319 if Type.equals (checkExp body, Type.unit)
320 then ()
321 else Error.bug "Xml.TypeCheck.typeCheck: program must be of type unit"
322 val _ =
323 case overflow of
324 NONE => true
325 | SOME x =>
326 let val {tyvars, ty} = getVar x
327 in
328 Vector.isEmpty tyvars
329 andalso Type.equals (ty, Type.exn)
330 end
331 val _ = Program.clear program
332 in
333 ()
334 end
335
336val typeCheck =
337 Trace.trace ("Xml.TypeCheck.typeCheck", Program.layout, Unit.layout) typeCheck
338
339val typeCheck = Control.trace (Control.Pass, "typeCheck") typeCheck
340
341end