elab.ml (29470B)
1 open Util 2 open Node 3 module E = Error 4 open Eval 5 open Quote 6 open Unify 7 module A = Abstract 8 module I = Internal 9 module V = Value 10 11 (*module R = Porig.NoneOneTons*) 12 13 exception BlockedOnFuture of Uniq.uniq * int * Name.Var.t 14 15 type mode = 16 | Infer 17 | Check of V.value 18 19 (* A clause is a conjunction of tests, and we view an array of clauses 20 * disjunctively. The casei:int is the index of the body that the match 21 * expression evaluates to if the clause matches. *) 22 type clause = { 23 tests: I.data_discriminant Uniq.UniqMap.t; 24 casei: int; 25 } 26 27 (* Convention: An elaboration-related function can have two versions, one whose 28 * name ends with a prime, which can throw an E.Exn, and one whose name does 29 * not end with a prime, which returns in the result monad. 30 * TODO: Make sure every function has both versions, even if unused? *) 31 32 let add_name' 33 : Name.Var.Set.t -> Name.Var.t node -> Name.Var.Set.t * Name.Var.t 34 = fun name_set {loc; data = name} -> 35 if Name.Var.Set.mem name name_set then 36 E.abort loc @@ E.ElabDuplicateName name 37 else 38 (Name.Var.Set.add name name_set, name) 39 40 let rec assign_patt 41 : V.context -> I.patt -> V.value -> Uniq.uniq -> V.context 42 = fun ctx {names; disc} vtyp var -> 43 let (ctx, _) = Ctx.assign ctx names vtyp (V.Arb var) in 44 45 match disc with 46 | I.DWild _ -> ctx 47 | I.DData {tag; tagi; subpatts; datatype} -> 48 let {I.binders; I.order} = datatype.ctors.(tagi) in 49 let arity = Array.length subpatts in 50 let subvars = Uniq.fresh arity in 51 let data = V.Data { 52 tag; 53 tagi; 54 args = Array.init arity (fun i -> V.Arb (Uniq.get subvars i)); 55 (* datatype is formed in a context without subvars bound. *) 56 datatype_clo = (ctx.env, datatype); 57 } in 58 let ctx = Ctx.bind ctx subvars in 59 let ctx = Ctx.define ctx var data in 60 61 (* Assign each subpattern in type-dependency order, because that's the 62 * order that check_disc' elaborates subpatterns in. The order matters 63 * here, because assign_patt binds variables. *) 64 let ctx' = ref ctx in 65 for i = 0 to arity - 1 do 66 let j = order.(i) in 67 let subtyp = I.disc_type binders.(j).patt.disc in 68 let vsubtyp = eval ctx.env subtyp in 69 ctx' := assign_patt !ctx' subpatts.(j) vsubtyp (Uniq.get subvars j) 70 done; 71 72 !ctx' 73 74 (* Elaborate explicits to Some and implicits to None. *) 75 let elaborate_args' 76 : 'a. Loc.t -> 'a array -> I.binder array -> 'a option array 77 = fun loc explicit_args binders -> 78 let arity = Array.length binders in 79 let explicit_count = Array.length explicit_args in 80 let implicit_count = ref 0 in 81 82 let args = Array.make arity garbage in 83 for i = 0 to arity - 1 do 84 (* TODO: Once we allow passing an implicit argument explicitly, 85 * this logic will need to change a bit. *) 86 args.(i) <- match binders.(i).plicity with 87 | Plicity.Ex -> 88 let j = i - !implicit_count in 89 begin if explicit_count <= j then 90 E.abort loc E.ElabArityMismatch 91 end; 92 Some (explicit_args.(j)) 93 | Plicity.Im -> 94 incr implicit_count; 95 None 96 done; 97 98 (* We had enough explicit args, but now ensure we don't have too many. *) 99 begin if explicit_count > arity - !implicit_count then 100 E.abort loc E.ElabArityMismatch 101 end; 102 103 args 104 105 let rec infer 106 : V.context -> A.term -> (I.term * V.value, E.error) result 107 = fun ctx t -> 108 try Ok (infer' ctx t) with 109 | E.Exn e -> Error e 110 111 and infer' 112 : V.context -> A.term -> I.term * V.value 113 = fun ctx t -> elaborate' ctx t Infer 114 115 and check 116 : V.context -> A.term -> V.value -> (I.term, E.error) result 117 = fun ctx t vtyp -> 118 try Ok (check' ctx t vtyp) with 119 | E.Exn e -> Error e 120 121 and check' 122 : V.context -> A.term -> V.value -> I.term 123 = fun ctx t vtyp -> 124 let (t, _) = elaborate' ctx t (Check (force ctx.env vtyp)) in 125 t 126 127 and elaborate 128 : V.context -> A.term -> mode -> (I.term * V.value, E.error) result 129 = fun ctx t mode -> 130 try Ok (elaborate' ctx t mode) with 131 | E.Exn e -> Error e 132 133 and elaborate' 134 : V.context -> A.term -> mode -> I.term * V.value 135 = fun ctx {loc; data = t} mode -> match t, mode with 136 | A.Let (definers, body), mode -> 137 let (ctx, definers) = infer_definers' ctx definers in 138 let (body, vtyp) = elaborate' ctx body mode in 139 (I.Let (definers, body), vtyp) 140 141 | A.Match _, Infer -> E.abort loc E.ElabCantInferMatch 142 143 | A.Match (scrutinee, cases), Check vtyp -> 144 (elaborate_match' ctx loc scrutinee cases vtyp, vtyp) 145 146 | A.Annot (tm, typ), Infer -> 147 let typ = check' ctx typ Std.v_Type in 148 let vtyp = eval ctx.env typ in 149 let tm = check' ctx tm vtyp in 150 (tm, vtyp) 151 152 | A.App (fn, explicit_args), Infer -> 153 let (fn, vtyp) = infer' ctx fn in 154 begin match force ctx.env vtyp with 155 | V.FnTypeClosure (clo, {multibinder; term = codomain}) -> 156 let (args, clo) = check_args' ctx loc explicit_args clo multibinder in 157 let vcodomain = eval clo codomain in 158 (I.App (fn, args), vcodomain) 159 | vtyp -> E.abort loc @@ E.ElabApplyNonFunction (quote ctx.env vtyp) 160 end 161 162 | A.Fn {data = {multibinder = params; term = body}; _}, Infer -> 163 let (ctx', multibinder) = infer_multibinder' ctx loc params in 164 let (body, vcodomain) = infer' ctx' body in 165 let codomain = quote ctx'.env vcodomain in 166 let fn = I.Fn {multibinder; term = body} in 167 let vfntype = V.FnTypeClosure (ctx.env, {multibinder; term = codomain}) in 168 (fn, vfntype) 169 170 | A.Fn {data = {multibinder = {data = params; _}; term = body}; _}, 171 Check (V.FnTypeClosure (clo, fntype) as vfntype) -> 172 let {I.multibinder = {binders = domains; order}; I.term = codomain} = fntype in 173 174 begin if Array.length params <> Array.length domains then 175 E.abort loc E.ElabFnArityMismatch 176 end; 177 let arity = Array.length params in 178 179 let vars = Uniq.fresh arity in 180 let ctx = Ctx.bind ctx vars in 181 let clo = Env.bind clo vars in 182 183 let ctx = ref ctx in 184 let name_set = ref Name.Var.Set.empty in 185 let params' = Array.make arity garbage in 186 for i = 0 to arity - 1 do 187 let j = order.(i) in 188 let param = params.(j).data in 189 let domain = domains.(j) in 190 191 begin if param.plicity <> domain.plicity then 192 E.abort loc E.ElabFnPlicityMismatch 193 end; 194 let plicity = param.plicity in 195 196 let vtyp = eval clo (I.disc_type domain.patt.disc) in 197 let typ = quote !ctx.env vtyp in 198 let (name_set', names) = check_irrefutable_patt' 199 !ctx !name_set param.patt vtyp in 200 name_set := name_set'; 201 202 let (ctx', _) = Ctx.assign !ctx names vtyp (V.Arb (Uniq.get vars j)) in 203 ctx := ctx'; 204 params'.(j) <- {I.plicity; I.patt = {names; disc = I.DWild typ}} 205 done; 206 207 let vcodomain = eval clo codomain in 208 let body = check' !ctx body vcodomain in 209 210 (I.Fn {multibinder = {binders = params'; order}; term = body}, vfntype) 211 212 | A.Fn _, Check vtyp -> 213 let typ = quote ctx.env vtyp in 214 E.abort loc @@ E.ElabExpectedFnType typ 215 216 | A.FnType {data = {multibinder = domains; term = codomain}; _}, Infer -> 217 let (ctx, multibinder) = infer_multibinder' ctx loc domains in 218 let codomain = check' ctx codomain Std.v_Type in 219 (I.FnType {multibinder; term = codomain}, Std.v_Type) 220 221 | A.Data _, Infer -> E.abort loc E.ElabCantInferData 222 223 | A.Data ({data = tag; _}, explicit_args), 224 Check (V.DataTypeClosure (clo, datatype) as vdatatype) -> 225 begin match Name.Tag.Map.find_opt tag datatype.names with 226 | Some tagi -> 227 let (args, _) = check_args' ctx loc explicit_args clo 228 datatype.ctors.(tagi) in 229 let datatype = shift_datatype ctx.env clo datatype in 230 (I.Data {tag; tagi; args; datatype}, vdatatype) 231 | None -> E.abort loc @@ E.ElabUnexpectedTag tag 232 end 233 234 | A.Data _, Check vtyp -> 235 let typ = quote ctx.env vtyp in 236 E.abort loc @@ E.ElabExpectedDataType typ 237 238 | A.TupleData args, Infer -> 239 let arity = Array.length args in 240 241 (* Only needed so that the indices in the type are correct. *) 242 let vars = Uniq.fresh arity in 243 let clo = Env.bind ctx.env vars in 244 245 let args' = Array.make arity garbage in 246 let binders = Array.make arity garbage in 247 for i = 0 to arity - 1 do 248 let (arg', vtyp) = infer' ctx args.(i) in 249 args'.(i) <- arg'; 250 let typ = quote clo vtyp in 251 binders.(i) <- { 252 I.plicity = Plicity.Ex; 253 I.patt = { 254 names = [||]; 255 disc = DWild typ; 256 }; 257 } 258 done; 259 260 let tag = Name.Tag.Of (string_of_int arity) in 261 let datatype = { 262 I.ctors = [|{binders; order = Array.init arity Fun.id}|]; 263 I.names = Name.Tag.Map.singleton tag 0; 264 } in 265 (I.Data {tag; tagi = 0; args = args'; datatype}, 266 V.DataTypeClosure (clo, datatype)) 267 268 | A.TupleData args, Check vtyp -> 269 (* XXX: Kinda hacky. *) 270 let tag = Name.Tag.Of (string_of_int (Array.length args)) in 271 elaborate' ctx (loc @$ A.Data (Loc.Nowhere @$ tag, args)) (Check vtyp) 272 273 | A.DataType ctors, Infer -> 274 let next = ref 0 in 275 let ctors' = Array.make (Name.Tag.Map.cardinal ctors) garbage in 276 let go binders = 277 let i = !next in 278 incr next; 279 let (_, multibinder) = infer_multibinder' ctx loc binders in 280 ctors'.(i) <- multibinder; 281 i in 282 let names = Name.Tag.Map.map go ctors in 283 (I.DataType {ctors = ctors'; names}, Std.v_Type) 284 285 | A.Nat n, Infer -> (I.Nat n, Std.v_Nat) 286 287 | A.Var ({data = name; _}, i), Infer -> 288 begin match Ctx.lookup ctx name i with 289 | Some {typ = V.Future (id, j); _} -> raise (BlockedOnFuture (id, j, name)) 290 | Some {typ; value; _} -> (quote ctx.env value, typ) 291 | None -> E.abort loc @@ E.ElabUnboundVar (name, i) 292 end 293 294 | A.Builtin b, Infer -> (I.Builtin b, Std.infer b) 295 296 | (A.Annot _ | A.App _ | A.FnType _ | A.DataType _ | A.Nat _ 297 | A.Var _ | A.Builtin _) as t, Check vexpected -> 298 let (t, vinferred) = infer' ctx {loc; data = t} in 299 begin try unify ctx.env vexpected vinferred with 300 | UnifyFail -> 301 let expected = quote ctx.env vexpected in 302 let inferred = quote ctx.env vinferred in 303 E.abort loc @@ E.ElabUnifyFail (expected, inferred) 304 end; 305 (t, vexpected) 306 307 (* Check the given explicit arguments against the given multibinder. 308 * Return the elaborated terms and the multibinder's closure extended with 309 * fresh variables defined to the arguments' values. *) 310 and check_args' 311 : V.context -> Loc.t -> A.term array -> V.environment -> I.multibinder 312 -> I.term array * V.environment 313 = fun ctx loc explicit_args clo {binders; order} -> 314 let arity = Array.length binders in 315 let args = elaborate_args' loc explicit_args binders in 316 317 let vars = Uniq.fresh arity in 318 let clo = Env.bind clo vars in 319 320 let args' = Array.make arity garbage in 321 let clo = ref clo in 322 for i = 0 to arity - 1 do 323 let j = order.(i) in 324 let vtyp = eval !clo (I.disc_type binders.(j).patt.disc) in 325 let arg = match args.(j) with 326 | Some arg -> check' ctx arg vtyp 327 | None -> no_impl "implicit args" in 328 args'.(j) <- arg; 329 let varg = eval ctx.env arg in 330 clo := Env.define !clo (Uniq.get vars j) varg 331 done; 332 333 (args', !clo) 334 335 (* Infer the given definers. Return the elaborated definers and the context 336 * extended with fresh variables for the definers defined to each rhs. *) 337 (* TODO: We need to check for circularity. Idea for algorithm: Have elaboration 338 * routines track not only variable usage, but also the least "delay" 339 * asssociated with each variable usage. E.g., a variable x uses x with delay 0 340 * (it's used immediately), a function uses the variables used in its body with 341 * their delay + 1, and a β-redex uses the variables in the lambda with their 342 * delay - 1. *) 343 and infer_definers' 344 : V.context -> A.definer array -> V.context * I.definer array 345 = fun ctx definers -> 346 let ndefiners = Array.length definers in 347 348 (* To simplify context handling, we work in a weakened contexted from the 349 * very beginning, even though the lhs of each definer is not allowed to 350 * refer to these variables. *) 351 let vars = Uniq.fresh ndefiners in 352 let ctx = Ctx.bind ctx vars in 353 354 match definers with 355 | [||] -> impossible "Elab.infer_definers': no definers" 356 357 (* Single non-recursive definer. These are handled specially, because 358 * the type annotation on the lhs is optional. *) 359 (* TODO: Maybe we should make this distinction in internal syntax (maybe 360 * abstract syntax as well). I.e., Let vs LetRec. *) 361 | [|{loc; data = {recursive = false; lhs; rhs}}|] -> 362 let (names, rhs, vtyp) = 363 (* First try to infer from lhs (and check rhs). *) 364 match infer_irrefutable_patt ctx Name.Var.Set.empty lhs with 365 | Ok (_, names, vtyp) -> 366 let rhs = check' ctx rhs vtyp in 367 (names, rhs, vtyp) 368 | Error {data = E.ElabNonInferablePatt; _} -> 369 (* Next try to infer from rhs (and check lhs). *) 370 let (rhs, vtyp) = infer' ctx rhs in 371 let (_, names) = check_irrefutable_patt' 372 ctx Name.Var.Set.empty lhs vtyp in 373 (names, rhs, vtyp) 374 | Error e -> E.abort e.loc e.data in 375 let typ = quote ctx.env vtyp in 376 (* XXX: vrhs doesn't need to be a RefClo. We could eagerly evaluate it, 377 * or add some other mechanism for laziness (like glued eval). *) 378 let vrhs = V.RefClo (ref ctx.env, rhs) in 379 let (ctx, _) = Ctx.assign ctx names vtyp (V.Arb (Uniq.get vars 0)) in 380 let ctx = Ctx.define ctx (Uniq.get vars 0) vrhs in 381 (ctx, [|{names; rhs; typ}|]) 382 383 (* Single recursive definer or many mutually-recursive definers. In either 384 * case, a type annotation on the lhs is mandatory. Probably, we could use 385 * meta-variables/unification to permit omitting annotations in some cases 386 * (e.g., like OCaml does with let rec ... and ...), but we generally try 387 * to avoid meta-variables/unification, because they're unpredictable; 388 * inference should only rely on local information. *) 389 | definers -> 390 (* Infer each lhs (in the original context, because definitions are 391 * not allowed to have mutually dependent types), and make all 392 * assignments. We later set the active flag to false on assignments 393 * for non-recusive definers, so that the rhs of non-recursive definers 394 * can not access their own assignment. *) 395 (* TODO: Actually, we should allow definer types to depend on each 396 * other in a well-ordered fashion, because this allows 397 * induction-recursion. *) 398 let ctx_with_asns = ref ctx in 399 let name_set = ref Name.Var.Set.empty in 400 let namess = Array.make ndefiners garbage in 401 let asns = Array.make ndefiners garbage in 402 for i = 0 to ndefiners - 1 do 403 let {loc; data = {A.lhs; _}} = definers.(i) in 404 match infer_irrefutable_patt ctx !name_set lhs with 405 | Ok (name_set', names, vtyp) -> 406 name_set := name_set'; 407 namess.(i) <- names; 408 let (ctx_with_asns', asn) = Ctx.assign !ctx_with_asns 409 names vtyp (V.Arb (Uniq.get vars i)) in 410 ctx_with_asns := ctx_with_asns'; 411 asns.(i) <- asn 412 | Error ({data = E.ElabNonInferablePatt; _} as root) -> 413 E.abort loc @@ E.ElabNoLetAnnot root 414 | Error e -> E.abort e.loc e.data 415 done; 416 let ctx = !ctx_with_asns in 417 418 (* Check each rhs with the appropriate assignments active, but not any 419 * definitions. This means that each definition is "opaque" during the 420 * elaboration of each rhs, i.e., the let-bound variables behave like 421 * fn-bound variables. It's hard to get around this. It might be useful 422 * to elaborate each rhs with every other rhs defined in context, but 423 * that would require every rhs to already be elaborated! Of course, 424 * after elaboration each rhs can see every other rhs, and we achieve 425 * by lazily evaluating each rhs using V.Rec. *) 426 let env = ref ctx.env in 427 let definers' = Array.make ndefiners garbage in 428 for i = 0 to ndefiners - 1 do 429 let vtyp = asns.(i).typ in 430 let typ = quote ctx.env vtyp in 431 432 let rhs = definers.(i).data.rhs in 433 let rhs = 434 if definers.(i).data.recursive then 435 check' ctx rhs vtyp 436 else begin 437 (* The lhs of non-recursive definers is not in scope when 438 * checking the rhs, so mark the lhs as inactive. *) 439 asns.(i).active <- false; 440 let rhs = check' ctx rhs vtyp in 441 asns.(i).active <- true; 442 rhs 443 end in 444 let vrhs = V.RefClo (env, rhs) in 445 446 env := Env.define !env (Uniq.get vars i) vrhs; 447 definers'.(i) <- {I.names = namess.(i); I.rhs; I.typ} 448 done; 449 450 (* TODO: For this situation, it might be nice to abstract the surface 451 * name assignment map from contexts. Then we can say a context is an 452 * environment + a surface name assignment. *) 453 ({ctx with env = !env}, definers') 454 455 and elaborate_match' 456 : V.context -> Loc.t -> A.term -> A.case array -> V.value -> I.term 457 = fun ctx loc scrutinee cases body_vtyp -> 458 let (scrutinee, scrutinee_vtyp) = infer' ctx scrutinee in 459 let vars = Uniq.fresh 1 in 460 let var = Uniq.get vars 0 in 461 462 let ncases = Array.length cases in 463 let cases' = Array.make ncases garbage in 464 for i = 0 to ncases - 1 do 465 let {data = {A.patt; A.body}; _} = cases.(i) in 466 467 let (_, patt) = check_patt' 468 ctx Name.Var.Set.empty patt scrutinee_vtyp in 469 470 let ctx = Ctx.bind ctx vars in 471 let ctx = assign_patt ctx patt scrutinee_vtyp var in 472 let body = check' ctx body body_vtyp in 473 474 cases'.(i) <- {I.patt; I.body} 475 done; 476 477 let to_clause 478 : int -> I.case -> clause 479 = fun casei case -> 480 let tests = match case.patt.disc with 481 | I.DWild _ -> Uniq.UniqMap.empty 482 | I.DData data_disc -> Uniq.UniqMap.singleton var data_disc in 483 {tests; casei} in 484 let clauses = Array.mapi to_clause cases' in 485 486 let used_cases = Array.make ncases false in 487 let env = Env.bind Env.empty vars in 488 let switch = elaborate_switch' loc used_cases env clauses in 489 490 begin match Array.find_index not used_cases with 491 | Some i -> E.abort cases.(i).loc E.ElabRedundantCase 492 | None -> () 493 end; 494 495 I.Match {scrutinee; cases = cases'; switch} 496 497 and elaborate_switch' 498 : Loc.t -> bool array -> V.environment -> clause array -> I.switch 499 = fun match_loc used_cases env clauses -> 500 let clause_count = Array.length clauses in 501 502 if clause_count > 0 then 503 match Uniq.UniqMap.min_binding_opt clauses.(0).tests with 504 (* Base case: An empty clause is a vacuous conjunction and hence always 505 * matches. *) 506 | None -> 507 let casei = clauses.(0).casei in 508 used_cases.(casei) <- true; 509 I.Goto casei 510 511 (* Inductive case: Switch on an arbitrary variable in the first clause. 512 * (Actually, here we switch on the least variable (i.e., such that 513 * discriminants are analyzed breadth-first), but that's just so 514 * that the output is predicatable when debugging.) 515 * TODO: We may want to use some heuristic to pick the variable. *) 516 | Some (var, {datatype = {ctors; names}; _}) -> 517 (* Recursively create a switch tree for each constructor. *) 518 let ctor_count = Array.length ctors in 519 let subswitches = Array.make ctor_count garbage in 520 for tagi = 0 to ctor_count - 1 do 521 let arity = Array.length ctors.(tagi).binders in 522 subswitches.(tagi) <- elaborate_subswitch' 523 match_loc used_cases env clauses var arity tagi 524 done; 525 526 let index = match Env.quote env var with 527 | Some ij -> ij 528 | None -> impossible "Elab.elaborate_switch: switch on unknown var" in 529 I.Switch {index; subswitches; names} 530 else 531 (* TODO: Give an example of a missing case. *) 532 E.abort match_loc E.ElabNonExhaustiveMatch 533 534 and elaborate_subswitch' 535 : Loc.t -> bool array -> V.environment -> clause array -> Uniq.uniq -> int 536 -> int -> I.switch 537 = fun match_loc used_cases env clauses var arity tagi -> 538 let clause_count = Array.length clauses in 539 let subvars = Uniq.fresh arity in 540 541 (* Count the number of clauses in the subproblem. *) 542 let subclause_count = ref 0 in 543 for i = 0 to clause_count - 1 do 544 match Uniq.UniqMap.find_opt var clauses.(i).tests with 545 | Some {tagi = tagi'; _} when tagi' = tagi -> 546 (* Clause i has a test of form "var = C ...", where C is 547 * constructor tagi. *) 548 incr subclause_count 549 | Some _ -> 550 (* Clause i has a test of form "var = D ...", where D <> C. *) 551 () 552 | None -> 553 (* Clause i has no opinion on var. *) 554 incr subclause_count 555 done; 556 557 (* Collect the subclauses. *) 558 let subclauses = Inc_array.make !subclause_count in 559 for i = 0 to clause_count - 1 do 560 let {tests; casei} = clauses.(i) in 561 match Uniq.UniqMap.find_opt var tests with 562 | Some {tagi = tagi'; subpatts; _} when tagi' = tagi -> 563 (* Clause i has a test of form "var = C (d_1,...,d_n)", where C is 564 * constructor tagi. In the subproblem, replace this clause by 565 * clauses "subvar_j = d_j" for each j such that d_j is a data 566 * discriminant. *) 567 let tests = Uniq.UniqMap.remove var tests in 568 let tests = ref tests in 569 for j = 0 to Array.length subpatts - 1 do 570 match subpatts.(j).disc with 571 | I.DWild _ -> () 572 | I.DData data_disc -> 573 let subvar = Uniq.get subvars j in 574 tests := Uniq.UniqMap.add subvar data_disc !tests 575 done; 576 Inc_array.add subclauses {tests = !tests; casei} 577 | Some _ -> 578 (* Clause i has a test of form "var = D ...", where D <> C, so 579 * do ignore this clause. *) 580 () 581 | None -> 582 (* Clause i has no opinion on var, so add this clause unchanged 583 * into the subproblem. *) 584 Inc_array.add subclauses {tests; casei} 585 done; 586 let subclauses = Inc_array.to_array subclauses in 587 588 let env = Env.bind env subvars in 589 elaborate_switch' match_loc used_cases env subclauses 590 591 (* TODO: This has evolved into a complete disaster. Rewrite it. *) 592 and infer_multibinder' 593 : V.context -> Loc.t -> A.multibinder -> V.context * I.multibinder 594 = fun ctx loc {data = binders; _} -> 595 (* We generate a globally unique id for this multibinder so that we can 596 * determine which BlockedOnFuture exceptions belong to us (see below). 597 * This uniq is not a variable. *) 598 let id = Uniq.get (Uniq.fresh 1) 0 in 599 600 let arity = Array.length binders in 601 let vars = Uniq.fresh arity in 602 let ctx = Ctx.bind ctx vars in 603 604 (* Add future assignments to ctx. *) 605 let ctx = ref ctx in 606 let name_set = ref Name.Var.Set.empty in 607 let asns = Array.make arity garbage in 608 for i = 0 to arity - 1 do 609 (* TODO: We should probably check that the pattern is irrefutable 610 * here. *) 611 let names = binders.(i).data.patt.data.names in 612 let (name_set, names) = Array.fold_left_map add_name' !name_set names in 613 let typ = V.Future (id, i) in 614 let value = V.Arb (Uniq.get vars i) in 615 let (ctx', asn) = Ctx.assign !ctx names typ value in 616 ctx := ctx'; 617 asns.(i) <- asn 618 done; 619 let ctx = !ctx in 620 621 (* The data structure used to track binder states. *) 622 let open struct 623 module IntSet = Set.Make(Int) 624 625 type state = 626 | Pending of { 627 dependency: (int * Name.Var.t) option; 628 dependents: IntSet.t; 629 } 630 | Elaborated of int 631 632 let start_state = Pending { 633 dependency = None; 634 dependents = IntSet.empty; 635 } 636 637 let find_cycle states start = 638 let rec search cycle i = match states.(i) with 639 | Pending {dependency = Some (j, name); _} -> 640 if i = j then 641 name :: cycle 642 else 643 search (name :: cycle) j 644 | Pending {dependency = None; _} -> 645 impossible "Elab.infer_multibinder': find_cycle called with \ 646 pending binder with no dependency" 647 | Elaborated _ -> 648 impossible "Elab.infer_multibinder': find_cycle called with \ 649 elaborated binder" in 650 search [] start 651 end in 652 653 let states = Array.make arity start_state in 654 let namess = Array.make arity garbage in 655 656 (* Next index in the topological sorting of <T. *) 657 let next = ref 0 in 658 659 let rec try_binder i = 660 let dependents = match states.(i) with 661 | Pending {dependency = None; dependents} -> dependents 662 | Pending {dependency = Some _; _} -> 663 impossible "Elab.infer_multibinder': try_binder called with \ 664 pending binder with a dependency" 665 | Elaborated _ -> 666 impossible "Elab.infer_multibinder': try_binder called with \ 667 elaborated binder" in 668 match infer_binder' ctx binders.(i) with 669 | (names, vtyp) -> 670 namess.(i) <- names; 671 asns.(i).typ <- vtyp; 672 states.(i) <- Elaborated !next; 673 incr next; 674 IntSet.iter remove_dependency dependents 675 | exception BlockedOnFuture (id', j, name) when id' = id -> 676 states.(i) <- Pending {dependency = Some (j, name); dependents}; 677 states.(j) <- match states.(j) with 678 | Pending r -> 679 Pending {r with dependents = IntSet.add i r.dependents} 680 | Elaborated _ -> 681 impossible "Elab.infer_multibinder': BlockedOnFuture raised \ 682 for elaborated binder" 683 684 and remove_dependency j = 685 let dependents = match states.(j) with 686 | Pending {dependency = Some _; dependents} -> dependents 687 | Pending {dependency = None; _} -> 688 impossible "Elab.infer_multibinder': remove_dependency called \ 689 with pending binder with no dependency" 690 | Elaborated _ -> 691 impossible "Elab.infer_multibinder': remove_dependency called \ 692 with elaborated binder" in 693 states.(j) <- Pending {dependency = None; dependents}; 694 try_binder j in 695 696 for i = 0 to arity - 1 do 697 try_binder i 698 done; 699 700 let binders' = Array.make arity garbage in 701 let order = Array.make arity 0 in 702 for i = 0 to arity - 1 do 703 match states.(i) with 704 | Elaborated j -> 705 let typ = quote ctx.env asns.(i).typ in 706 binders'.(i) <- { 707 I.plicity = binders.(i).data.plicity; 708 I.patt = { 709 names = namess.(i); 710 disc = I.DWild typ; 711 }; 712 }; 713 order.(j) <- i 714 | Pending _ -> 715 E.abort loc @@ E.ElabBinderCycle (find_cycle states i) 716 done; 717 718 (ctx, {binders = binders'; order}) 719 720 and infer_binder' 721 : V.context -> A.binder -> Name.Var.t array * V.value 722 = fun ctx {loc; data = {plicity; patt}} -> 723 match infer_irrefutable_patt ctx Name.Var.Set.empty patt, plicity with 724 | Ok (_, names, vtyp), _ -> (names, vtyp) 725 | Error {data = E.ElabNonInferablePatt; _}, Plicity.Im -> 726 begin match check_irrefutable_patt ctx Name.Var.Set.empty patt 727 Std.v_Type with 728 | Ok (_, names) -> (names, Std.v_Type) 729 | Error root -> E.abort loc @@ E.ElabUnannotImplicitIsType root 730 end 731 | Error ({data = E.ElabNonInferablePatt; _} as root), Plicity.Ex -> 732 E.abort loc @@ E.ElabNoBinderAnnot root 733 | Error e, _ -> E.abort e.loc e.data 734 735 (* Check that each term in the array starting at the given index is a type 736 * convertible to the given value. *) 737 and check_types' 738 : V.context -> A.term array -> int -> V.value -> unit 739 = fun ctx typs start vtyp -> 740 for i = start to Array.length typs - 1 do 741 let typ' = check' ctx typs.(i) Std.v_Type in 742 let vtyp' = eval ctx.env typ' in 743 try unify ctx.env vtyp vtyp' with 744 | UnifyFail -> 745 let typ = quote ctx.env vtyp in 746 E.abort typs.(i).loc @@ E.ElabUnifyFail (typ, typ') 747 done 748 749 and infer_irrefutable_patt 750 : V.context -> Name.Var.Set.t -> A.patt 751 -> (Name.Var.Set.t * Name.Var.t array * V.value, E.error) result 752 = fun ctx name_set patt -> 753 try Ok (infer_irrefutable_patt' ctx name_set patt) with 754 | E.Exn e -> Error e 755 756 and infer_irrefutable_patt' 757 : V.context -> Name.Var.Set.t -> A.patt 758 -> Name.Var.Set.t * Name.Var.t array * V.value 759 = fun ctx name_set ({loc; _} as patt) -> 760 let (name_set, patt, vtyp) = infer_patt' ctx name_set patt in 761 match patt with 762 | {disc = I.DData _; _} -> E.abort loc E.ElabDataPattRefutable 763 | {names; disc = I.DWild _} -> (name_set, names, vtyp) 764 765 and check_irrefutable_patt 766 : V.context -> Name.Var.Set.t -> A.patt -> V.value 767 -> (Name.Var.Set.t * Name.Var.t array, E.error) result 768 = fun ctx name_set patt vtyp -> 769 try Ok (check_irrefutable_patt' ctx name_set patt vtyp) with 770 | E.Exn e -> Error e 771 772 and check_irrefutable_patt' 773 : V.context -> Name.Var.Set.t -> A.patt -> V.value 774 -> Name.Var.Set.t * Name.Var.t array 775 = fun ctx name_set ({loc; _} as patt) vtyp -> 776 let (name_set, patt) = check_patt' ctx name_set patt vtyp in 777 match patt with 778 | {disc = I.DData _; _} -> E.abort loc E.ElabDataPattRefutable 779 | {names; disc = I.DWild _} -> (name_set, names) 780 781 and infer_patt' 782 : V.context -> Name.Var.Set.t -> A.patt -> Name.Var.Set.t * I.patt * V.value 783 = fun ctx name_set {loc; data = patt} -> match patt with 784 | {typs = [||]; _} -> E.abort loc E.ElabNonInferablePatt 785 | {names; typs; disc} -> 786 let (name_set, names) = Array.fold_left_map add_name' name_set names in 787 let typ = check' ctx typs.(0) Std.v_Type in 788 let vtyp = eval ctx.env typ in 789 check_types' ctx typs 1 vtyp; 790 let (names_set, disc) = check_disc' ctx name_set disc vtyp in 791 (name_set, {names; disc}, vtyp) 792 793 and check_patt' 794 : V.context -> Name.Var.Set.t -> A.patt -> V.value -> Name.Var.Set.t * I.patt 795 = fun ctx name_set {loc; data = {names; typs; disc}} vtyp -> 796 let (name_set, names) = Array.fold_left_map add_name' name_set names in 797 check_types' ctx typs 0 vtyp; 798 let (name_set, disc) = check_disc' ctx name_set disc vtyp in 799 (name_set, {names; disc}) 800 801 and check_disc' 802 : V.context -> Name.Var.Set.t -> A.discriminant -> V.value 803 -> Name.Var.Set.t * I.discriminant 804 = fun ctx name_set {loc; data = disc} vtyp -> match disc, force ctx.env vtyp with 805 | A.DWild, vtyp -> (name_set, I.DWild (quote ctx.env vtyp)) 806 | A.DData {tag = {data = tag; _}; subpatts = explicit_subpatts}, 807 V.DataTypeClosure (clo, datatype) -> 808 begin match Name.Tag.Map.find_opt tag datatype.names with 809 | Some tagi -> (* XXX: This is very similar to check_args'. *) 810 let datatype' = shift_datatype ctx.env clo datatype in 811 let {I.binders; I.order} = datatype.ctors.(tagi) in 812 let arity = Array.length binders in 813 let vars = Uniq.fresh arity in 814 let ctx = Ctx.bind ctx vars in 815 let clo = Env.bind clo vars in 816 817 let name_set = ref name_set in 818 let subpatts = elaborate_args' loc explicit_subpatts binders in 819 let subpatts' = Array.make arity garbage in 820 let ctx = ref ctx in 821 for i = 0 to arity - 1 do 822 let j = order.(i) in 823 let typ = I.disc_type binders.(j).patt.disc in 824 let vtyp = eval clo typ in 825 let (name_set', subpatt') = match subpatts.(j) with 826 | Some patt -> check_patt' !ctx !name_set patt vtyp 827 | None -> no_impl "implicit args" in 828 name_set := name_set'; 829 subpatts'.(j) <- subpatt'; 830 (* XXX: I think this is a quadratic time algorithm. We should 831 * thread a context through the check_disc calls instead of 832 * repeatedly reassigning/rebinding/redefining stuff. *) 833 ctx := assign_patt !ctx subpatt' vtyp (Uniq.get vars j) 834 done; 835 836 let disc = I.DData { 837 tag; 838 tagi; 839 subpatts = subpatts'; 840 datatype = datatype'; 841 } in 842 (!name_set, disc) 843 844 | None -> E.abort loc @@ E.ElabUnexpectedTag tag 845 end 846 | A.DData _, vtyp -> E.abort loc @@ E.ElabExpectedDataType (quote ctx.env vtyp)