Home My Page Projects Code Snippets Project Openings SML/NJ
Summary Activity Forums Tracker Lists Tasks Docs Surveys News SCM Files

SCM Repository

[smlnj] Annotation of /sml/trunk/src/compiler/FLINT/flint/chkflint.sml
ViewVC logotype

Annotation of /sml/trunk/src/compiler/FLINT/flint/chkflint.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 733 - (view) (download)

1 : monnier 45 (* COPYRIGHT (c) 1997, 1998 YALE FLINT PROJECT *)
2 : monnier 16 (* chkflint.sml *)
3 :    
4 :     (* FLINT Type Checker *)
5 :    
6 :     signature CHKFLINT = sig
7 :    
8 :     (** which set of the typing rules to use while doing the typecheck *)
9 : monnier 71 type typsys (* currently very crude *)
10 : monnier 16
11 :     val checkTop : FLINT.fundec * typsys -> bool
12 :     val checkExp : FLINT.lexp * typsys -> bool
13 :    
14 :     end (* signature CHKFLINT *)
15 :    
16 :     structure ChkFlint : CHKFLINT =
17 :     struct
18 :    
19 : monnier 45 (** which set of the typing rules to use while doing the typecheck *)
20 : monnier 71 type typsys = bool (* currently very crude *)
21 : monnier 45
22 : monnier 16 local structure LT = LtyExtern
23 :     structure LV = LambdaVar
24 :     structure DA = Access
25 :     structure DI = DebIndex
26 :     structure PP = PPFlint
27 : monnier 71 structure PO = PrimOp
28 : blume 733 structure S = IntRedBlackSet
29 : monnier 16 open FLINT
30 :    
31 :     fun bug s = ErrorMsg.impossible ("ChkFlint: "^s)
32 : monnier 220 val say = Control_Print.say
33 : monnier 16 val anyerror = ref false
34 :    
35 :     (****************************************************************************
36 :     * BASIC UTILITY FUNCTIONS *
37 :     ****************************************************************************)
38 :    
39 : monnier 45 fun foldl2 (f,a,xs,ys,g) = let
40 :     val rec loop =
41 :     fn (a, nil, nil) => a
42 :     | (a, x::xs, y::ys) => loop (f (x,y,a), xs, ys)
43 :     | (a, xs', _) => g (a, xs', length xs, length ys)
44 :     in loop (a,xs,ys) end
45 :    
46 :     fun simplify (le,0) = RET [STRING "<...>"]
47 :     | simplify (le,n) =
48 :     let fun h le = simplify (le, n-1)
49 :     fun h1 (fk,v,args,le) = (fk, v, args, h le)
50 : monnier 220 fun h2 (tfk,v,tvs,le) = (tfk, v, tvs, h le)
51 : monnier 16 in case le
52 : monnier 45 of LET (vs,e1,e2) => LET (vs, h e1, h e2)
53 :     | FIX (fdecs,b) => FIX (map h1 fdecs, h b)
54 :     | TFN (tdec,e) => TFN (h2 tdec, h e)
55 :     | SWITCH (v,l,dc,opp) =>
56 :     let fun g (c,x) = (c, h x)
57 :     val f = fn SOME y => SOME (h y) | NONE => NONE
58 :     in SWITCH (v, l, map g dc, f opp)
59 :     end
60 :     | CON (dc,tcs,vs,lv,le) => CON (dc, tcs, vs, lv, h le)
61 :     | RECORD (rk,vs,lv,le) => RECORD (rk, vs, lv, h le)
62 :     | SELECT (v,n,lv,le) => SELECT (v, n, lv, h le)
63 :     | HANDLE (e,v) => HANDLE (h e, v)
64 :     | PRIMOP (po,vs,lv,le) => PRIMOP (po, vs, lv, h le)
65 : monnier 16 | _ => le
66 :     end (* end of simplify *)
67 :    
68 :     (** utility functions for printing *)
69 :     val tkPrint = say o LT.tk_print
70 :     val tcPrint = say o LT.tc_print
71 :     val ltPrint = say o LT.lt_print
72 : monnier 45 fun lePrint le = PP.printLexp (simplify (le, 3))
73 :     val svPrint = PP.printSval
74 : monnier 16
75 : monnier 45 fun error (le,g) = (
76 :     anyerror := true;
77 :     say "\n************************************************************\
78 :     \\n**** FLINT type checking failed: ";
79 :     g () before (say "\n** term:\n"; lePrint le))
80 : monnier 16
81 : monnier 45 fun errMsg (le,s,r) = error (le, fn () => (say s; r))
82 : monnier 16
83 : monnier 45 fun catchExn f (le,g) =
84 :     f () handle ex => error
85 :     (le, fn () => g () before say ("\n** exception " ^ exnName ex ^ " raised"))
86 : monnier 16
87 : monnier 45 (*** a hack for type checkng ***)
88 : monnier 71 fun laterPhase postReify = postReify
89 : monnier 16
90 : monnier 45 fun check phase envs lexp = let
91 : league 75 (* imperative table -- keeps track of already bound variables,
92 :     * so we can tell if a variable is re-bound (which should be
93 :     * illegal). Note that lvars and tvars actually share the same
94 :     * namespace! --league, 11 April 1998
95 :     *)
96 : blume 733 val definedLvars = ref S.empty
97 : league 75 fun lvarDef le (lvar:lvar) =
98 : blume 733 if S.member(!definedLvars, lvar) then
99 : league 75 errMsg (le, ("lvar " ^ (LambdaVar.prLvar lvar) ^ " redefined"), ())
100 :     else
101 : blume 733 definedLvars := S.add(!definedLvars, lvar)
102 : league 75
103 : monnier 45 val ltEquiv = LT.lt_eqv_x (* should be LT.lt_eqv *)
104 : monnier 71 val ltTAppChk =
105 : monnier 220 if !FLINT_Control.checkKinds then LT.lt_inst_chk_gen()
106 : monnier 71 else fn (lt,ts,_) => LT.lt_inst(lt,ts)
107 : monnier 16
108 : monnier 45 fun constVoid _ = LT.ltc_void
109 : monnier 71 val (ltString,ltExn,ltEtag,ltVector,ltWrap,ltBool) =
110 : monnier 45 if laterPhase phase then
111 : monnier 71 (LT.ltc_string, LT.ltc_void, constVoid, constVoid, constVoid,
112 :     LT.ltc_void)
113 : monnier 45 else
114 :     (LT.ltc_string, LT.ltc_exn, LT.ltc_etag, LT.ltc_tyc o LT.tcc_vector,
115 : monnier 71 LT.ltc_tyc o LT.tcc_box, LT.ltc_bool)
116 : monnier 16
117 : monnier 45 fun prMsgLt (s,lt) = (say s; ltPrint lt)
118 : monnier 16
119 : monnier 45 fun prList f s t = let
120 :     val rec loop =
121 :     fn [] => say "<empty list>\n"
122 :     | [x] => (f x; say "\n")
123 :     | x::xs => (f x; say "\n* and\n"; loop xs)
124 :     in say s; loop t end
125 : monnier 16
126 : monnier 45 fun print2Lts (s,s',lt,lt') = (prList ltPrint s lt; prList ltPrint s' lt')
127 : monnier 16
128 : monnier 45 fun ltMatch (le,s) (t,t') =
129 :     if ltEquiv (t,t') then ()
130 :     else error
131 :     (le, fn () =>
132 :     (prMsgLt (s ^ ": Lty conflict\n** types:\n", t);
133 :     prMsgLt ("\n** and\n", t')))
134 : monnier 16
135 : monnier 45 fun ltsMatch (le,s) (ts,ts') =
136 :     foldl2 (fn (t,t',_) => ltMatch (le,s) (t,t'),
137 :     (), ts, ts',
138 :     fn (_,_,n,n') => error
139 :     (le,
140 :     fn () => print2Lts
141 :     (concat [s, ": type list mismatch (", Int.toString n, " vs ",
142 :     Int.toString n', ")\n** expected types:\n"],
143 :     "** actual types:\n",
144 :     ts, ts')))
145 : monnier 16
146 : monnier 45 local
147 :     fun ltFnAppGen opr (le,s,msg) (t,ts) =
148 :     catchExn
149 : monnier 71 (fn () => let val (xs,ys) = opr (LT.ltd_fkfun t)
150 :     in ltsMatch (le,s) (xs,ts); ys
151 :     end)
152 : monnier 45 (le, fn () => (prMsgLt (s ^ msg ^ "\n** type:\n", t); []))
153 :     in
154 :     fun ltFnApp (le,s) =
155 :     ltFnAppGen (fn x => x) (le,s,": Applying term of non-arrow type")
156 :     fun ltFnAppR (le,s) =
157 :     ltFnAppGen (fn (x,y) => (y,x)) (le,s,": Rev-app term of non-arrow type")
158 :     end
159 : monnier 16
160 : monnier 45 fun ltTyApp (le,s) (lt,ts,kenv) =
161 :     catchExn
162 :     (fn () => ltTAppChk (lt,ts,kenv))
163 :     (le,
164 :     fn () =>
165 :     (prMsgLt (s ^ ": Kind conflict\n** function Lty:\n", lt);
166 :     prList tcPrint "\n** argument Tycs:\n" ts;
167 :     []))
168 : monnier 16
169 : monnier 184 fun ltArrow (le,s) (cconv,alts,rlts) =
170 :     (case cconv
171 :     of CC_FCT => LT.ltc_fct (alts,rlts)
172 :     | CC_FUN raw =>
173 : monnier 45 (catchExn
174 :     (fn () => LT.ltc_arrow (raw,alts,rlts))
175 :     (le,
176 :     fn () =>
177 :     (print2Lts
178 :     (s ^ ": deeply polymorphic non-functor\n** parameter types:\n",
179 :     "** result types:\n",
180 :     alts, rlts);
181 :     LT.ltc_void))))
182 : monnier 16
183 : monnier 45 (* typeInEnv : LT.tkindEnv * LT.ltyEnv * DI.depth -> lexp -> lty list *)
184 :     fun typeInEnv (kenv,venv,d) = let
185 :     fun extEnv (lv,lt,ve) = LT.ltInsert (ve,lv,lt,d)
186 :     fun bogusBind (lv,ve) = extEnv (lv,LT.ltc_void,ve)
187 :     fun typeIn venv' = typeInEnv (kenv,venv',d)
188 :     fun typeWith (v,t) = typeIn (LT.ltInsert (venv,v,t,d))
189 :     fun mismatch (le,s) (a,r,n,n') = errMsg
190 :     (le,
191 :     concat [s, ": binding/result list mismatch\n** expected ",
192 :     Int.toString n, " elements, got ", Int.toString n'],
193 :     foldl bogusBind a r)
194 : monnier 16
195 : monnier 45 fun typeof le = let
196 :     fun typeofVar lv = LT.ltLookup (venv,lv,d)
197 :     handle ltUnbound =>
198 :     errMsg (le, "Unbound Lvar " ^ LV.lvarName lv, LT.ltc_void)
199 :     val typeofVal =
200 :     fn VAR lv => typeofVar lv
201 :     | (INT _ | WORD _) => LT.ltc_int
202 :     | (INT32 _ | WORD32 _) => LT.ltc_int32
203 :     | REAL _ => LT.ltc_real
204 :     | STRING _ => LT.ltc_string
205 : league 75 fun typeofFn ve (_,lvar,vts,eb) = let
206 :     fun split ((lv,t), (ve,ts)) =
207 :     (lvarDef le lv;
208 :     (LT.ltInsert (ve,lv,t,d), t::ts))
209 : monnier 45 val (ve',ts) = foldr split (ve,[]) vts
210 : league 75 in
211 :     lvarDef le lvar;
212 :     (ts, typeIn ve' eb)
213 : monnier 45 end
214 : monnier 16
215 : league 74 (* There are lvars hidden in Access.conrep, used by dcon.
216 :     * These functions just make sure that they are defined in the
217 :     * current environemnent; we don't bother to typecheck them properly
218 :     * because supposedly conrep will go away...
219 :     *)
220 :     fun checkAccess (DA.LVAR v) = ignore (typeofVar v)
221 :     | checkAccess (DA.PATH (a,_)) = checkAccess a
222 :     | checkAccess _ = ()
223 :    
224 :     fun checkConrep (DA.EXN a) =
225 :     checkAccess a
226 :     | checkConrep (DA.SUSP (SOME (a1,a2))) =
227 :     (checkAccess a1;
228 :     checkAccess a2)
229 :     | checkConrep _ =
230 :     ()
231 :    
232 : monnier 45 fun chkSnglInst (fp as (le,s)) (lt,ts) =
233 :     if null ts then lt
234 :     else case ltTyApp fp (lt,ts,kenv)
235 :     of [] => LT.ltc_unit
236 :     | [lt] => lt
237 :     | lts => errMsg
238 :     (le,
239 :     concat [s, ": inst yields ", Int.toString (length lts),
240 :     " results instead of 1"],
241 :     LT.ltc_void)
242 :     fun typeWithBindingToSingleRsltOfInstAndApp (s,lt,ts,vs,lv) e = let
243 :     val fp = (le,s)
244 :     val lt = case ltFnApp fp (chkSnglInst fp (lt,ts), map typeofVal vs)
245 :     of [lt] => lt
246 :     | _ => errMsg
247 :     (le,
248 :     concat [s, ": primop/dcon must return single result type "],
249 :     LT.ltc_void)
250 :     (*
251 :     | [] => LT.ltc_unit
252 :     | lts => LT.ltc_tuple lts
253 :     (*** until PRIMOPs start returning multiple results... ***)
254 :     *)
255 :     in typeWith (lv,lt) e
256 :     end
257 : monnier 16
258 : monnier 45 fun matchAndTypeWith (s,v,lt,lt',lv,e) =
259 :     (ltMatch (le,s) (typeofVal v, lt); typeWith (lv, lt') e)
260 :     in case le
261 :     of RET vs => map typeofVal vs
262 :     | LET (lvs,e,e') =>
263 : league 75 (app (lvarDef le) lvs;
264 :     typeIn (foldl2 (extEnv, venv, lvs,
265 :     typeof e, mismatch (le,"LET"))) e')
266 : monnier 45 | FIX ([],e) =>
267 :     (say "\n**** Warning: empty declaration list in FIX\n"; typeof e)
268 : monnier 184 | FIX ((fd as (fk as {isrec=NONE,cconv,...},
269 :     lv, _, _)) :: fds', e) => let
270 : monnier 45 val (alts,rlts) = typeofFn venv fd
271 : monnier 184 val lt = ltArrow (le,"non-rec FIX") (cconv,alts,rlts)
272 : monnier 45 val ve = extEnv (lv,lt,venv)
273 :     val venv' =
274 :     if null fds' then ve
275 :     else errMsg
276 :     (le,
277 :     "multiple bindings in FIX, not all recursive",
278 :     foldl (fn ((_,lv,_,_), ve) => bogusBind (lv,ve)) ve fds')
279 :     in typeIn venv' e
280 :     end
281 :     | FIX (fds,e) => let
282 :     val isfct = false
283 : monnier 184 fun extEnv (({cconv=CC_FCT, ...}, _, _, _), _) =
284 : monnier 45 bug "unexpected case in extEnv"
285 : monnier 184 | extEnv (({isrec,cconv,...}, lv, vts, _) : fundec, ve) =
286 : monnier 45 case (isrec, isfct)
287 : monnier 184 of (SOME (lts,_), false) => let
288 :     val lt = ltArrow (le,"FIX") (cconv,
289 : monnier 45 map #2 vts, lts)
290 :     in LT.ltInsert (ve,lv,lt,d)
291 :     end
292 :     | _ => let
293 :     val msg =
294 :     if isfct then "recursive functor "
295 :     else "a non-recursive function "
296 :     in errMsg (le, "in FIX: " ^ msg ^ LV.lvarName lv, ve)
297 :     end
298 :     val venv' = foldl extEnv venv fds
299 : monnier 184 fun chkDcl (({isrec = NONE, ...}, _, _, _) : fundec) = ()
300 :     | chkDcl (fd as ({isrec = SOME (lts,_), ...}, _, _, _)) = let
301 : monnier 45 in ltsMatch (le,"FIX") (lts, #2 (typeofFn venv' fd))
302 :     end
303 :     in
304 :     app chkDcl fds;
305 :     typeIn venv' e
306 :     end
307 :     | APP (v,vs) => ltFnApp (le,"APP") (typeofVal v, map typeofVal vs)
308 : monnier 220 | TFN ((tfk,lv,tks,e), e') => let
309 : league 75 fun getkind (tv,tk) = (lvarDef le tv; tk)
310 :     val ks = map getkind tks
311 : monnier 45 val lts = typeInEnv (LT.tkInsert (kenv,ks), venv, DI.next d) e
312 : league 75 in
313 :     lvarDef le lv;
314 :     typeWith (lv, LT.ltc_poly (ks,lts)) e'
315 : monnier 45 end
316 :     | TAPP (v,ts) => ltTyApp (le,"TAPP") (typeofVal v, ts, kenv)
317 :     | SWITCH (_,_,[],_) => errMsg (le,"empty SWITCH",[])
318 :     | SWITCH (v, _, ce::ces, lo) => let
319 :     val selLty = typeofVal v
320 :     fun g lt = (ltMatch (le,"SWITCH branch 1") (lt,selLty); venv)
321 :     fun brLts (c,e) = let
322 :     val venv' = case c
323 : league 74 of DATAcon ((_,conrep,lt), ts, v) => let
324 :     val _ = checkConrep conrep
325 : monnier 45 val fp = (le,"SWITCH DECON")
326 :     val ct = chkSnglInst fp (lt,ts)
327 :     val nts = ltFnAppR fp (ct, [selLty])
328 : league 75 in
329 :     lvarDef le v;
330 :     foldl2 (extEnv, venv, [v], nts, mismatch fp)
331 : monnier 45 end
332 :     | (INTcon _ | WORDcon _) => g LT.ltc_int
333 :     | (INT32con _ | WORD32con _) => g LT.ltc_int32
334 :     | REALcon _ => g LT.ltc_real
335 :     | STRINGcon _ => g ltString
336 :     | VLENcon _ => g LT.ltc_int (* ? *)
337 :     in typeIn venv' e
338 :     end
339 :     val ts = brLts ce
340 :     fun chkBranch (ce,n) =
341 :     (ltsMatch (le, "SWITCH branch " ^ Int.toString n) (ts, brLts ce);
342 :     n+1)
343 :     in
344 :     foldl chkBranch 2 ces;
345 :     case lo
346 :     of SOME e => ltsMatch (le,"SWITCH else") (ts, typeof e)
347 :     | NONE => ();
348 :     ts
349 :     end
350 : league 74 | CON ((_,conrep,lt), ts, u, lv, e) =>
351 :     (checkConrep conrep;
352 : league 75 lvarDef le lv;
353 : league 74 typeWithBindingToSingleRsltOfInstAndApp ("CON",lt,ts,[u],lv) e)
354 : monnier 45 | RECORD (rk,vs,lv,e) => let
355 :     val lt = case rk
356 :     of RK_VECTOR t => let
357 :     val lt = LT.ltc_tyc t
358 :     val match = ltMatch (le,"VECTOR")
359 :     in
360 :     app (fn v => match (lt, typeofVal v)) vs;
361 :     ltVector t
362 :     end
363 :     | RK_TUPLE _ =>
364 :     if null vs then LT.ltc_unit
365 :     else let
366 :     fun chkMono v = let val t = typeofVal v
367 :     in
368 :     if LT.ltp_fct t orelse LT.ltp_poly t then
369 :     error (le, fn () =>
370 :     prMsgLt
371 :     ("RECORD: poly type in mono record:\n",t))
372 :     else ();
373 :     t
374 :     end
375 :     in LT.ltc_tuple (map chkMono vs)
376 :     end
377 :     | RK_STRUCT => LT.ltc_str (map typeofVal vs)
378 : league 75 in
379 :     lvarDef le lv;
380 :     typeWith (lv,lt) e
381 : monnier 45 end
382 :     | SELECT (v,n,lv,e) => let
383 :     val lt = catchExn
384 :     (fn () => LT.lt_select (typeofVal v, n))
385 :     (le,
386 :     fn () =>
387 :     (say "SELECT from wrong type or out of range"; LT.ltc_void))
388 : league 75 in
389 :     lvarDef le lv;
390 :     typeWith (lv,lt) e
391 : monnier 45 end
392 :     | RAISE (v,lts) => (ltMatch (le,"RAISE") (typeofVal v, ltExn); lts)
393 :     | HANDLE (e,v) => let val lts = typeof e
394 :     in ltFnAppR (le,"HANDLE") (typeofVal v, lts); lts
395 :     end
396 :     | BRANCH ((_,_,lt,ts), vs, e1, e2) =>
397 :     let val fp = (le, "BRANCH")
398 :     val lt =
399 :     case ltFnApp fp (chkSnglInst fp (lt,ts), map typeofVal vs)
400 :     of [lt] => lt
401 :     | _ => errMsg
402 :     (le,
403 :     "BRANCK : primop must return single result ",
404 :     LT.ltc_void)
405 : monnier 71 val _ = ltMatch fp (lt, ltBool)
406 : monnier 45 val lts1 = typeof e1
407 :     val lts2 = typeof e2
408 :     in ltsMatch fp (lts1, lts2);
409 :     lts1
410 :     end
411 : monnier 71 | PRIMOP ((_,PO.WCAST,lt,[]), [u], lv, e) =>
412 :     (*** a hack: checked only after reifY is done ***)
413 :     if laterPhase phase then
414 : league 75 (lvarDef le lv;
415 :     case LT.ltd_fct lt
416 : monnier 71 of ([argt], [rt]) =>
417 :     (ltMatch (le, "WCAST") (typeofVal u, argt);
418 :     typeWith (lv, rt) e)
419 :     | _ => bug "unexpected WCAST in typecheck")
420 :     else bug "unexpected WCAST in typecheck"
421 : league 74 | PRIMOP ((dc,_,lt,ts), vs, lv, e) => let
422 :     (* There are lvars hidden inside dicts, which we didn't check
423 :     * before. This is a first-order check that they at least
424 :     * are bound to something; for now we don't care about their
425 :     * types. (I'm not sure what the rules should look like)
426 :     * --league, 10 april 1998.
427 :     *)
428 :     fun checkDict (SOME {default, table}) =
429 :     (typeofVar default;
430 :     app (ignore o typeofVar o #2) table)
431 :     | checkDict (NONE : dict option) = ()
432 :     in
433 :     checkDict dc;
434 : league 75 lvarDef le lv;
435 : league 74 typeWithBindingToSingleRsltOfInstAndApp ("PRIMOP",lt,ts,vs,lv) e
436 :     end
437 : monnier 45 (*
438 :     | GENOP (dict, (_,lt,ts), vs, lv, e) =>
439 :     (* verify dict ? *)
440 :     typeWithBindingToSingleRsltOfInstAndApp ("GENOP",lt,ts,vs,lv) e
441 :     | ETAG (t,v,lv,e) =>
442 :     matchAndTypeWith ("ETAG", v, ltString, ltEtag (LT.ltc_tyc t), lv, e)
443 :     | WRAP (t,v,lv,e) =>
444 :     matchAndTypeWith ("WRAP", v, LT.ltc_tyc t, ltWrap t, lv, e)
445 :     | UNWRAP (t,v,lv,e) =>
446 :     matchAndTypeWith ("UNWRAP", v, ltWrap t, LT.ltc_tyc t, lv, e)
447 :     *)
448 :     end
449 :     in typeof end
450 : monnier 16
451 : monnier 45 in
452 :     anyerror := false;
453 :     ignore (typeInEnv envs lexp);
454 :     !anyerror
455 :     end
456 : monnier 16
457 : monnier 45 in (* loplevel local *)
458 : monnier 16
459 : monnier 45 (****************************************************************************
460 :     * MAIN FUNCTION --- val checkTop : FLINT.fundec * typsys -> bool *
461 :     ****************************************************************************)
462 :     fun checkTop ((fkind, v, args, lexp) : fundec, phase) = let
463 :     val ve =
464 :     foldl (fn ((v,t), ve) => LT.ltInsert (ve,v,t,DI.top)) LT.initLtyEnv args
465 :     val err = check phase (LT.initTkEnv, ve, DI.top) lexp
466 :     val err = case fkind
467 : monnier 184 of {cconv=CC_FCT,...} => err
468 : monnier 45 | _ => (say "**** Not a functor at top level\n"; true)
469 :     in err end
470 : monnier 16
471 : monnier 45 val checkTop =
472 :     Stats.doPhase (Stats.makePhase "Compiler 051 FLINTCheck") checkTop
473 : monnier 16
474 : monnier 45 (****************************************************************************
475 :     * MAIN FUNCTION --- val checkExp : FLINT.lexp * typsys -> bool *
476 :     * (currently unused?) *
477 :     ****************************************************************************)
478 :     fun checkExp (le,phase) = check phase (LT.initTkEnv, LT.initLtyEnv, DI.top) le
479 : monnier 16
480 :     end (* toplevel local *)
481 :     end (* structure ChkFlint *)

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0