wenzelm@42405
|
1 |
(* Title: Pure/type_infer_context.ML
|
wenzelm@42405
|
2 |
Author: Stefan Berghofer and Markus Wenzel, TU Muenchen
|
wenzelm@42405
|
3 |
|
wenzelm@42405
|
4 |
Type-inference preparation and standard type inference.
|
wenzelm@42405
|
5 |
*)
|
wenzelm@42405
|
6 |
|
wenzelm@42405
|
7 |
signature TYPE_INFER_CONTEXT =
|
wenzelm@42405
|
8 |
sig
|
wenzelm@42405
|
9 |
val const_sorts: bool Config.T
|
wenzelm@45445
|
10 |
val prepare_positions: Proof.context -> term list -> term list * (Position.T * typ) list
|
wenzelm@42405
|
11 |
val prepare: Proof.context -> term list -> int * term list
|
wenzelm@42405
|
12 |
val infer_types: Proof.context -> term list -> term list
|
wenzelm@42405
|
13 |
end;
|
wenzelm@42405
|
14 |
|
wenzelm@42405
|
15 |
structure Type_Infer_Context: TYPE_INFER_CONTEXT =
|
wenzelm@42405
|
16 |
struct
|
wenzelm@42405
|
17 |
|
wenzelm@42405
|
18 |
(** prepare types/terms: create inference parameters **)
|
wenzelm@42405
|
19 |
|
wenzelm@42405
|
20 |
(* constraints *)
|
wenzelm@42405
|
21 |
|
wenzelm@42405
|
22 |
val const_sorts = Config.bool (Config.declare "const_sorts" (K (Config.Bool true)));
|
wenzelm@42405
|
23 |
|
wenzelm@42405
|
24 |
fun const_type ctxt =
|
wenzelm@42405
|
25 |
try ((not (Config.get ctxt const_sorts) ? Type.strip_sorts) o
|
wenzelm@42405
|
26 |
Consts.the_constraint (Proof_Context.consts_of ctxt));
|
wenzelm@42405
|
27 |
|
wenzelm@42405
|
28 |
fun var_type ctxt = the_default dummyT o Proof_Context.def_type ctxt;
|
wenzelm@42405
|
29 |
|
wenzelm@42405
|
30 |
|
wenzelm@42405
|
31 |
(* prepare_typ *)
|
wenzelm@42405
|
32 |
|
wenzelm@42405
|
33 |
fun prepare_typ typ params_idx =
|
wenzelm@42405
|
34 |
let
|
wenzelm@42405
|
35 |
val (params', idx) = fold_atyps
|
wenzelm@42405
|
36 |
(fn TVar (xi, S) =>
|
wenzelm@42405
|
37 |
(fn ps_idx as (ps, idx) =>
|
wenzelm@42405
|
38 |
if Type_Infer.is_param xi andalso not (Vartab.defined ps xi)
|
wenzelm@42405
|
39 |
then (Vartab.update (xi, Type_Infer.mk_param idx S) ps, idx + 1) else ps_idx)
|
wenzelm@42405
|
40 |
| _ => I) typ params_idx;
|
wenzelm@42405
|
41 |
|
wenzelm@42405
|
42 |
fun prepare (T as Type (a, Ts)) idx =
|
wenzelm@42405
|
43 |
if T = dummyT then (Type_Infer.mk_param idx [], idx + 1)
|
wenzelm@42405
|
44 |
else
|
wenzelm@42405
|
45 |
let val (Ts', idx') = fold_map prepare Ts idx
|
wenzelm@42405
|
46 |
in (Type (a, Ts'), idx') end
|
wenzelm@42405
|
47 |
| prepare (T as TVar (xi, _)) idx =
|
wenzelm@42405
|
48 |
(case Vartab.lookup params' xi of
|
wenzelm@42405
|
49 |
NONE => T
|
wenzelm@42405
|
50 |
| SOME p => p, idx)
|
wenzelm@42405
|
51 |
| prepare (TFree ("'_dummy_", S)) idx = (Type_Infer.mk_param idx S, idx + 1)
|
wenzelm@42405
|
52 |
| prepare (T as TFree _) idx = (T, idx);
|
wenzelm@42405
|
53 |
|
wenzelm@42405
|
54 |
val (typ', idx') = prepare typ idx;
|
wenzelm@42405
|
55 |
in (typ', (params', idx')) end;
|
wenzelm@42405
|
56 |
|
wenzelm@42405
|
57 |
|
wenzelm@42405
|
58 |
(* prepare_term *)
|
wenzelm@42405
|
59 |
|
wenzelm@42405
|
60 |
fun prepare_term ctxt tm (vparams, params, idx) =
|
wenzelm@42405
|
61 |
let
|
wenzelm@42405
|
62 |
fun add_vparm xi (ps_idx as (ps, idx)) =
|
wenzelm@42405
|
63 |
if not (Vartab.defined ps xi) then
|
wenzelm@42405
|
64 |
(Vartab.update (xi, Type_Infer.mk_param idx []) ps, idx + 1)
|
wenzelm@42405
|
65 |
else ps_idx;
|
wenzelm@42405
|
66 |
|
wenzelm@42405
|
67 |
val (vparams', idx') = fold_aterms
|
wenzelm@42405
|
68 |
(fn Var (_, Type ("_polymorphic_", _)) => I
|
wenzelm@42405
|
69 |
| Var (xi, _) => add_vparm xi
|
wenzelm@42405
|
70 |
| Free (x, _) => add_vparm (x, ~1)
|
wenzelm@42405
|
71 |
| _ => I)
|
wenzelm@42405
|
72 |
tm (vparams, idx);
|
wenzelm@42405
|
73 |
fun var_param xi = the (Vartab.lookup vparams' xi);
|
wenzelm@42405
|
74 |
|
wenzelm@42405
|
75 |
fun polyT_of T idx =
|
wenzelm@42405
|
76 |
apsnd snd (prepare_typ (Type_Infer.paramify_vars T) (Vartab.empty, idx));
|
wenzelm@42405
|
77 |
|
wenzelm@42405
|
78 |
fun constraint T t ps =
|
wenzelm@42405
|
79 |
if T = dummyT then (t, ps)
|
wenzelm@42405
|
80 |
else
|
wenzelm@42405
|
81 |
let val (T', ps') = prepare_typ T ps
|
wenzelm@42405
|
82 |
in (Type.constraint T' t, ps') end;
|
wenzelm@42405
|
83 |
|
wenzelm@42405
|
84 |
fun prepare (Const ("_type_constraint_", T) $ t) ps_idx =
|
wenzelm@42405
|
85 |
let
|
wenzelm@45445
|
86 |
val A = Type.constraint_type ctxt T;
|
wenzelm@42405
|
87 |
val (A', ps_idx') = prepare_typ A ps_idx;
|
wenzelm@42405
|
88 |
val (t', ps_idx'') = prepare t ps_idx';
|
wenzelm@42405
|
89 |
in (Const ("_type_constraint_", A' --> A') $ t', ps_idx'') end
|
wenzelm@42405
|
90 |
| prepare (Const (c, T)) (ps, idx) =
|
wenzelm@42405
|
91 |
(case const_type ctxt c of
|
wenzelm@42405
|
92 |
SOME U =>
|
wenzelm@42405
|
93 |
let val (U', idx') = polyT_of U idx
|
wenzelm@42405
|
94 |
in constraint T (Const (c, U')) (ps, idx') end
|
wenzelm@42405
|
95 |
| NONE => error ("Undeclared constant: " ^ quote c))
|
wenzelm@42405
|
96 |
| prepare (Var (xi, Type ("_polymorphic_", [T]))) (ps, idx) =
|
wenzelm@42405
|
97 |
let val (T', idx') = polyT_of T idx
|
wenzelm@42405
|
98 |
in (Var (xi, T'), (ps, idx')) end
|
wenzelm@42405
|
99 |
| prepare (Var (xi, T)) ps_idx = constraint T (Var (xi, var_param xi)) ps_idx
|
wenzelm@42405
|
100 |
| prepare (Free (x, T)) ps_idx = constraint T (Free (x, var_param (x, ~1))) ps_idx
|
wenzelm@42405
|
101 |
| prepare (Bound i) ps_idx = (Bound i, ps_idx)
|
wenzelm@42405
|
102 |
| prepare (Abs (x, T, t)) ps_idx =
|
wenzelm@42405
|
103 |
let
|
wenzelm@42405
|
104 |
val (T', ps_idx') = prepare_typ T ps_idx;
|
wenzelm@42405
|
105 |
val (t', ps_idx'') = prepare t ps_idx';
|
wenzelm@42405
|
106 |
in (Abs (x, T', t'), ps_idx'') end
|
wenzelm@42405
|
107 |
| prepare (t $ u) ps_idx =
|
wenzelm@42405
|
108 |
let
|
wenzelm@42405
|
109 |
val (t', ps_idx') = prepare t ps_idx;
|
wenzelm@42405
|
110 |
val (u', ps_idx'') = prepare u ps_idx';
|
wenzelm@42405
|
111 |
in (t' $ u', ps_idx'') end;
|
wenzelm@42405
|
112 |
|
wenzelm@42405
|
113 |
val (tm', (params', idx'')) = prepare tm (params, idx');
|
wenzelm@42405
|
114 |
in (tm', (vparams', params', idx'')) end;
|
wenzelm@42405
|
115 |
|
wenzelm@42405
|
116 |
|
wenzelm@45445
|
117 |
(* prepare_positions *)
|
wenzelm@45445
|
118 |
|
wenzelm@45445
|
119 |
fun prepare_positions ctxt tms =
|
wenzelm@45445
|
120 |
let
|
wenzelm@45445
|
121 |
val visible = Context_Position.is_visible ctxt;
|
wenzelm@45445
|
122 |
|
wenzelm@45445
|
123 |
fun prepareT (Type (a, Ts)) ps_idx =
|
wenzelm@45445
|
124 |
let val (Ts', ps_idx') = fold_map prepareT Ts ps_idx
|
wenzelm@45445
|
125 |
in (Type (a, Ts'), ps_idx') end
|
wenzelm@45445
|
126 |
| prepareT T (ps, idx) =
|
wenzelm@45445
|
127 |
(case Term_Position.decode_positionT T of
|
wenzelm@45445
|
128 |
SOME pos =>
|
wenzelm@45445
|
129 |
if visible then
|
wenzelm@45445
|
130 |
let val U = Type_Infer.mk_param idx []
|
wenzelm@45445
|
131 |
in (U, ((pos, U) :: ps, idx + 1)) end
|
wenzelm@45445
|
132 |
else (dummyT, (ps, idx))
|
wenzelm@45445
|
133 |
| NONE => (T, (ps, idx)));
|
wenzelm@45445
|
134 |
|
wenzelm@45445
|
135 |
fun prepare (Const ("_type_constraint_", T)) ps_idx =
|
wenzelm@45445
|
136 |
let
|
wenzelm@45445
|
137 |
val A = Type.constraint_type ctxt T;
|
wenzelm@45445
|
138 |
val (A', ps_idx') = prepareT A ps_idx;
|
wenzelm@45445
|
139 |
in (Const ("_type_constraint_", A' --> A'), ps_idx') end
|
wenzelm@45445
|
140 |
| prepare (Const (c, T)) ps_idx =
|
wenzelm@45445
|
141 |
let val (T', ps_idx') = prepareT T ps_idx
|
wenzelm@45445
|
142 |
in (Const (c, T'), ps_idx') end
|
wenzelm@45445
|
143 |
| prepare (Free (x, T)) ps_idx =
|
wenzelm@45445
|
144 |
let val (T', ps_idx') = prepareT T ps_idx
|
wenzelm@45445
|
145 |
in (Free (x, T'), ps_idx') end
|
wenzelm@45445
|
146 |
| prepare (Var (xi, T)) ps_idx =
|
wenzelm@45445
|
147 |
let val (T', ps_idx') = prepareT T ps_idx
|
wenzelm@45445
|
148 |
in (Var (xi, T'), ps_idx') end
|
wenzelm@45445
|
149 |
| prepare (t as Bound _) ps_idx = (t, ps_idx)
|
wenzelm@45445
|
150 |
| prepare (Abs (x, T, t)) ps_idx =
|
wenzelm@45445
|
151 |
let
|
wenzelm@45445
|
152 |
val (T', ps_idx') = prepareT T ps_idx;
|
wenzelm@45445
|
153 |
val (t', ps_idx'') = prepare t ps_idx';
|
wenzelm@45445
|
154 |
in (Abs (x, T', t'), ps_idx'') end
|
wenzelm@45445
|
155 |
| prepare (t $ u) ps_idx =
|
wenzelm@45445
|
156 |
let
|
wenzelm@45445
|
157 |
val (t', ps_idx') = prepare t ps_idx;
|
wenzelm@45445
|
158 |
val (u', ps_idx'') = prepare u ps_idx';
|
wenzelm@45445
|
159 |
in (t' $ u', ps_idx'') end;
|
wenzelm@45445
|
160 |
|
wenzelm@45445
|
161 |
val idx = Type_Infer.param_maxidx_of tms + 1;
|
wenzelm@45445
|
162 |
val (tms', (ps, _)) = fold_map prepare tms ([], idx);
|
wenzelm@45445
|
163 |
in (tms', ps) end;
|
wenzelm@45445
|
164 |
|
wenzelm@45445
|
165 |
|
wenzelm@42405
|
166 |
|
wenzelm@42405
|
167 |
(** order-sorted unification of types **)
|
wenzelm@42405
|
168 |
|
wenzelm@42405
|
169 |
exception NO_UNIFIER of string * typ Vartab.table;
|
wenzelm@42405
|
170 |
|
wenzelm@42405
|
171 |
fun unify ctxt =
|
wenzelm@42405
|
172 |
let
|
wenzelm@42405
|
173 |
val thy = Proof_Context.theory_of ctxt;
|
wenzelm@42405
|
174 |
val arity_sorts = Type.arity_sorts (Context.pretty ctxt) (Sign.tsig_of thy);
|
wenzelm@42405
|
175 |
|
wenzelm@42405
|
176 |
|
wenzelm@42405
|
177 |
(* adjust sorts of parameters *)
|
wenzelm@42405
|
178 |
|
wenzelm@42405
|
179 |
fun not_of_sort x S' S =
|
wenzelm@42405
|
180 |
"Variable " ^ x ^ "::" ^ Syntax.string_of_sort ctxt S' ^ " not of sort " ^
|
wenzelm@42405
|
181 |
Syntax.string_of_sort ctxt S;
|
wenzelm@42405
|
182 |
|
wenzelm@42405
|
183 |
fun meet (_, []) tye_idx = tye_idx
|
wenzelm@42405
|
184 |
| meet (Type (a, Ts), S) (tye_idx as (tye, _)) =
|
wenzelm@42405
|
185 |
meets (Ts, arity_sorts a S handle ERROR msg => raise NO_UNIFIER (msg, tye)) tye_idx
|
wenzelm@42405
|
186 |
| meet (TFree (x, S'), S) (tye_idx as (tye, _)) =
|
wenzelm@42405
|
187 |
if Sign.subsort thy (S', S) then tye_idx
|
wenzelm@42405
|
188 |
else raise NO_UNIFIER (not_of_sort x S' S, tye)
|
wenzelm@42405
|
189 |
| meet (TVar (xi, S'), S) (tye_idx as (tye, idx)) =
|
wenzelm@42405
|
190 |
if Sign.subsort thy (S', S) then tye_idx
|
wenzelm@42405
|
191 |
else if Type_Infer.is_param xi then
|
wenzelm@42405
|
192 |
(Vartab.update_new
|
wenzelm@42405
|
193 |
(xi, Type_Infer.mk_param idx (Sign.inter_sort thy (S', S))) tye, idx + 1)
|
wenzelm@42405
|
194 |
else raise NO_UNIFIER (not_of_sort (Term.string_of_vname xi) S' S, tye)
|
wenzelm@42405
|
195 |
and meets (T :: Ts, S :: Ss) (tye_idx as (tye, _)) =
|
wenzelm@42405
|
196 |
meets (Ts, Ss) (meet (Type_Infer.deref tye T, S) tye_idx)
|
wenzelm@42405
|
197 |
| meets _ tye_idx = tye_idx;
|
wenzelm@42405
|
198 |
|
wenzelm@42405
|
199 |
|
wenzelm@42405
|
200 |
(* occurs check and assignment *)
|
wenzelm@42405
|
201 |
|
wenzelm@42405
|
202 |
fun occurs_check tye xi (TVar (xi', _)) =
|
wenzelm@42405
|
203 |
if xi = xi' then raise NO_UNIFIER ("Occurs check!", tye)
|
wenzelm@42405
|
204 |
else
|
wenzelm@42405
|
205 |
(case Vartab.lookup tye xi' of
|
wenzelm@42405
|
206 |
NONE => ()
|
wenzelm@42405
|
207 |
| SOME T => occurs_check tye xi T)
|
wenzelm@42405
|
208 |
| occurs_check tye xi (Type (_, Ts)) = List.app (occurs_check tye xi) Ts
|
wenzelm@42405
|
209 |
| occurs_check _ _ _ = ();
|
wenzelm@42405
|
210 |
|
wenzelm@42405
|
211 |
fun assign xi (T as TVar (xi', _)) S env =
|
wenzelm@42405
|
212 |
if xi = xi' then env
|
wenzelm@42405
|
213 |
else env |> meet (T, S) |>> Vartab.update_new (xi, T)
|
wenzelm@42405
|
214 |
| assign xi T S (env as (tye, _)) =
|
wenzelm@42405
|
215 |
(occurs_check tye xi T; env |> meet (T, S) |>> Vartab.update_new (xi, T));
|
wenzelm@42405
|
216 |
|
wenzelm@42405
|
217 |
|
wenzelm@42405
|
218 |
(* unification *)
|
wenzelm@42405
|
219 |
|
wenzelm@42405
|
220 |
fun show_tycon (a, Ts) =
|
wenzelm@42405
|
221 |
quote (Syntax.string_of_typ ctxt (Type (a, replicate (length Ts) dummyT)));
|
wenzelm@42405
|
222 |
|
wenzelm@42405
|
223 |
fun unif (T1, T2) (env as (tye, _)) =
|
wenzelm@42405
|
224 |
(case pairself (`Type_Infer.is_paramT o Type_Infer.deref tye) (T1, T2) of
|
wenzelm@42405
|
225 |
((true, TVar (xi, S)), (_, T)) => assign xi T S env
|
wenzelm@42405
|
226 |
| ((_, T), (true, TVar (xi, S))) => assign xi T S env
|
wenzelm@42405
|
227 |
| ((_, Type (a, Ts)), (_, Type (b, Us))) =>
|
wenzelm@42405
|
228 |
if a <> b then
|
wenzelm@42405
|
229 |
raise NO_UNIFIER
|
wenzelm@42405
|
230 |
("Clash of types " ^ show_tycon (a, Ts) ^ " and " ^ show_tycon (b, Us), tye)
|
wenzelm@42405
|
231 |
else fold unif (Ts ~~ Us) env
|
wenzelm@42405
|
232 |
| ((_, T), (_, U)) => if T = U then env else raise NO_UNIFIER ("", tye));
|
wenzelm@42405
|
233 |
|
wenzelm@42405
|
234 |
in unif end;
|
wenzelm@42405
|
235 |
|
wenzelm@42405
|
236 |
|
wenzelm@42405
|
237 |
|
wenzelm@42405
|
238 |
(** simple type inference **)
|
wenzelm@42405
|
239 |
|
wenzelm@42405
|
240 |
(* infer *)
|
wenzelm@42405
|
241 |
|
wenzelm@42405
|
242 |
fun infer ctxt =
|
wenzelm@42405
|
243 |
let
|
wenzelm@42405
|
244 |
(* errors *)
|
wenzelm@42405
|
245 |
|
wenzelm@42405
|
246 |
fun prep_output tye bs ts Ts =
|
wenzelm@42405
|
247 |
let
|
wenzelm@42405
|
248 |
val (Ts_bTs', ts') = Type_Infer.finish ctxt tye (Ts @ map snd bs, ts);
|
wenzelm@42405
|
249 |
val (Ts', Ts'') = chop (length Ts) Ts_bTs';
|
wenzelm@42405
|
250 |
fun prep t =
|
wenzelm@42405
|
251 |
let val xs = rev (Term.variant_frees t (rev (map fst bs ~~ Ts'')))
|
wenzelm@42405
|
252 |
in Term.subst_bounds (map Syntax_Trans.mark_boundT xs, t) end;
|
wenzelm@42405
|
253 |
in (map prep ts', Ts') end;
|
wenzelm@42405
|
254 |
|
wenzelm@42405
|
255 |
fun err_loose i = error ("Loose bound variable: B." ^ string_of_int i);
|
wenzelm@42405
|
256 |
|
wenzelm@42405
|
257 |
fun unif_failed msg =
|
wenzelm@42405
|
258 |
"Type unification failed" ^ (if msg = "" then "" else ": " ^ msg) ^ "\n\n";
|
wenzelm@42405
|
259 |
|
wenzelm@42405
|
260 |
fun err_appl msg tye bs t T u U =
|
wenzelm@42405
|
261 |
let val ([t', u'], [T', U']) = prep_output tye bs [t, u] [T, U]
|
wenzelm@42405
|
262 |
in error (unif_failed msg ^ Type.appl_error ctxt t' T' u' U' ^ "\n") end;
|
wenzelm@42405
|
263 |
|
wenzelm@42405
|
264 |
|
wenzelm@42405
|
265 |
(* main *)
|
wenzelm@42405
|
266 |
|
wenzelm@42405
|
267 |
fun inf _ (Const (_, T)) tye_idx = (T, tye_idx)
|
wenzelm@42405
|
268 |
| inf _ (Free (_, T)) tye_idx = (T, tye_idx)
|
wenzelm@42405
|
269 |
| inf _ (Var (_, T)) tye_idx = (T, tye_idx)
|
wenzelm@42405
|
270 |
| inf bs (Bound i) tye_idx =
|
wenzelm@43278
|
271 |
(snd (nth bs i handle General.Subscript => err_loose i), tye_idx)
|
wenzelm@42405
|
272 |
| inf bs (Abs (x, T, t)) tye_idx =
|
wenzelm@42405
|
273 |
let val (U, tye_idx') = inf ((x, T) :: bs) t tye_idx
|
wenzelm@42405
|
274 |
in (T --> U, tye_idx') end
|
wenzelm@42405
|
275 |
| inf bs (t $ u) tye_idx =
|
wenzelm@42405
|
276 |
let
|
wenzelm@42405
|
277 |
val (T, tye_idx') = inf bs t tye_idx;
|
wenzelm@42405
|
278 |
val (U, (tye, idx)) = inf bs u tye_idx';
|
wenzelm@42405
|
279 |
val V = Type_Infer.mk_param idx [];
|
wenzelm@42405
|
280 |
val tye_idx'' = unify ctxt (U --> V, T) (tye, idx + 1)
|
wenzelm@42405
|
281 |
handle NO_UNIFIER (msg, tye') => err_appl msg tye' bs t T u U;
|
wenzelm@42405
|
282 |
in (V, tye_idx'') end;
|
wenzelm@42405
|
283 |
|
wenzelm@42405
|
284 |
in inf [] end;
|
wenzelm@42405
|
285 |
|
wenzelm@42405
|
286 |
|
wenzelm@42405
|
287 |
(* main interfaces *)
|
wenzelm@42405
|
288 |
|
wenzelm@42405
|
289 |
fun prepare ctxt raw_ts =
|
wenzelm@42405
|
290 |
let
|
wenzelm@42405
|
291 |
val constrain_vars = Term.map_aterms
|
wenzelm@42405
|
292 |
(fn Free (x, T) => Type.constraint T (Free (x, var_type ctxt (x, ~1)))
|
wenzelm@42405
|
293 |
| Var (xi, T) => Type.constraint T (Var (xi, var_type ctxt xi))
|
wenzelm@42405
|
294 |
| t => t);
|
wenzelm@42405
|
295 |
|
wenzelm@42405
|
296 |
val ts = burrow_types (Syntax.check_typs ctxt) raw_ts;
|
wenzelm@42405
|
297 |
val idx = Type_Infer.param_maxidx_of ts + 1;
|
wenzelm@42405
|
298 |
val (ts', (_, _, idx')) =
|
wenzelm@42405
|
299 |
fold_map (prepare_term ctxt o constrain_vars) ts
|
wenzelm@42405
|
300 |
(Vartab.empty, Vartab.empty, idx);
|
wenzelm@42405
|
301 |
in (idx', ts') end;
|
wenzelm@42405
|
302 |
|
wenzelm@42405
|
303 |
fun infer_types ctxt raw_ts =
|
wenzelm@42405
|
304 |
let
|
wenzelm@42405
|
305 |
val (idx, ts) = prepare ctxt raw_ts;
|
wenzelm@42405
|
306 |
val (tye, _) = fold (snd oo infer ctxt) ts (Vartab.empty, idx);
|
wenzelm@42405
|
307 |
val (_, ts') = Type_Infer.finish ctxt tye ([], ts);
|
wenzelm@42405
|
308 |
in ts' end;
|
wenzelm@42405
|
309 |
|
wenzelm@42405
|
310 |
end;
|