package elpi
ELPI - Embeddable λProlog Interpreter
Install
Dune Dependency
Authors
Maintainers
Sources
elpi-2.0.7.tbz
sha256=80233ebd92babd696148ed553238961ec7b6de6bf157045aae1c7090840aeded
sha512=00c9ec01fabde9db1de4a58cb37480035e6f926d83b8360553419bcb99e9199f0720dde975f97ac9942ce528884d3d59d025cfbd471f12d57547429f15684d49
doc/src/elpi.compiler/type_checker.ml.html
Source file type_checker.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
(* elpi: embedded lambda prolog interpreter *) (* license: GNU Lesser General Public License Version 2.1 or later *) (* ------------------------------------------------------------------------- *) open Elpi_util open Util open Elpi_parser open Ast open Compiler_data type type_abbrevs = (TypeAssignment.skema_w_id * Loc.t) F.Map.t type arities = Arity.t F.Map.t let check_disjoint ~type_abbrevs ~kinds = kinds |> F.Map.iter (fun k (_,lock) -> if F.Map.mem k type_abbrevs then let { ScopedTypeExpression.loc } = F.Map.find k type_abbrevs in error ~loc (Format.asprintf "Type abbreviations and types must be dijoint. Type %a declared in %a" F.pp k Loc.pp lock)) open ScopedTypeExpression let check_param_unique ~loc c ctx = if F.Set.mem c ctx then error ~loc ("Duplicate type parameter " ^ F.show c) let check_param_exists ~loc c ctx = if not @@ F.Set.mem c ctx then error ~loc (Format.asprintf "Unknown type parameter %a. Known parameters: %a" F.pp c (pplist F.pp ", ") (F.Set.elements ctx)) let check_global_exists ~loc c (type_abbrevs : type_abbrevs) arities nargs = if F.Map.mem c arities then begin let arity, _ = F.Map.find c arities in if arity != nargs then error ~loc (Format.asprintf "Type %a expects %d arguments but was given %d" F.pp c arity nargs) end else if F.Map.mem c type_abbrevs then begin let arity = TypeAssignment.nparams @@ fst @@ F.Map.find c type_abbrevs in if arity != nargs then error ~loc (Format.asprintf "Type %a expects %d arguments but was given %d" F.pp c arity nargs) end else error ~loc ("Unknown type " ^ F.show c) let rec check_loc_tye ~type_abbrevs ~kinds ctx { loc; it } = check_tye ~loc ~type_abbrevs ~kinds ctx it and check_tye ~loc ~type_abbrevs ~kinds ctx = function | Any -> TypeAssignment.Any | Const(Bound _,c) -> check_param_exists ~loc c ctx; UVar c | Const(Global _,c) -> check_global_exists ~loc c type_abbrevs kinds 0; Cons c | App(_,c,x,xs) -> check_global_exists ~loc c type_abbrevs kinds (1 + List.length xs); App(c,check_loc_tye ~type_abbrevs ~kinds ctx x, List.map (check_loc_tye ~type_abbrevs ~kinds ctx) xs) | Arrow(v,s,t) -> Arr(v,check_loc_tye ~type_abbrevs ~kinds ctx s,check_loc_tye ~type_abbrevs ~kinds ctx t) | Pred(_,[]) -> Prop | Pred(f,(_,x)::xs) -> Arr(NotVariadic,check_loc_tye ~type_abbrevs ~kinds ctx x,check_tye ~type_abbrevs ~kinds ~loc ctx (Pred(f,xs))) let check_type ~type_abbrevs ~kinds ~loc ctx x : TypeAssignment.skema_w_id = (* Format.eprintf "check_type under %a\n%!" (F.Map.pp (fun fmt (n,_) -> ())) kinds; Format.eprintf "check_type %a\n%!" ScopedTypeExpression.pp_v_ x; *) let rec aux_params ~loc ctx = function | Lam(c,t) -> check_param_unique ~loc c ctx; TypeAssignment.Lam(c,aux_params ~loc (F.Set.add c ctx) t) | Ty t -> TypeAssignment.Ty(check_loc_tye ~type_abbrevs ~kinds ctx t) in Scope.fresh_type_decl_id (), aux_params ~loc ctx x let check_types ~type_abbrevs ~kinds lst : TypeAssignment.overloaded_skema_with_id = match List.map (fun { value; loc } -> check_type ~type_abbrevs ~kinds ~loc F.Set.empty value) lst with | [] -> assert false | [x] -> TypeAssignment.Single x | xs -> TypeAssignment.Overloaded xs let check_type ~type_abbrevs ~kinds { value; loc } : (TypeAssignment.skema_w_id) = check_type ~type_abbrevs ~kinds ~loc F.Set.empty value let arrow_of_args args ety = let rec aux = function | [] -> ety | x :: xs -> TypeAssignment.Arr(Ast.Structured.NotVariadic,ScopedTerm.type_of x,aux xs) in aux args let arrow_of_tys tys ety = let rec aux = function | [] -> ety | x :: xs -> TypeAssignment.Arr(Ast.Structured.NotVariadic,x,aux xs) in aux tys type env = TypeAssignment.overloaded_skema_with_id F.Map.t type env_undeclared = (TypeAssignment.t * Scope.type_decl_id * Ast.Loc.t) F.Map.t open ScopedTerm let error_not_a_function ~loc c tyc args x = let t = if args = [] then ScopedTerm.Const(Scope.mkGlobal ~escape_ns:true (),c) else ScopedTerm.(App(Scope.mkGlobal ~escape_ns:true (),c,List.hd args, List.tl args)) in let msg = Format.asprintf "@[<hov>%a is not a function but it is passed the argument@ @[<hov>%a@].@ The type of %a is %a@]" ScopedTerm.pretty_ t ScopedTerm.pretty x F.pp c TypeAssignment.pretty tyc in error ~loc msg let pp_tyctx fmt = function | None -> Format.fprintf fmt "its context" | Some c -> Format.fprintf fmt "%a" F.pp c let error_bad_cdata_ety ~loc ~tyctx ~ety c tx = let msg = Format.asprintf "@[<hov>literal \"%a\" has type %a@ but %a expects a term of type@ %a@]" CData.pp c TypeAssignment.pretty tx pp_tyctx tyctx TypeAssignment.pretty ety in error ~loc msg let error_bad_ety ~loc ~tyctx ~ety pp c tx = let msg = Format.asprintf "@[<hov>%a has type %a@ but %a expects a term of type@ %a@]" pp c TypeAssignment.pretty tx pp_tyctx tyctx TypeAssignment.pretty ety in error ~loc msg let error_bad_ety2 ~loc ~tyctx ~ety1 ~ety2 pp c tx = let msg = Format.asprintf "@[<hov>%a has type %a@ but %a expects a term of type@ %a@ or %a@]" pp c TypeAssignment.pretty tx pp_tyctx tyctx TypeAssignment.pretty ety1 TypeAssignment.pretty ety2 in error ~loc msg let error_bad_function_ety ~loc ~tyctx ~ety c t = let msg = Format.asprintf "@[<hov>%a is a function@ but %a expects a term of type@ %a@]" ScopedTerm.pretty_ ScopedTerm.(Lam(c,None,t)) pp_tyctx tyctx TypeAssignment.pretty ety in error ~loc msg let error_bad_const_ety_l ~loc ~tyctx ~ety c txl = let msg = Format.asprintf "@[<hv>%a is overloaded but none of its types matches the type expected by %a:@, @[<hov>%a@]@,Its types are:@,@[<v 2> %a@]@]" F.pp c pp_tyctx tyctx TypeAssignment.pretty ety (pplist ~boxed:true (fun fmt (_,x)-> Format.fprintf fmt "%a" TypeAssignment.pretty x) ", ") txl in error ~loc msg let error_overloaded_app ~loc ~ety c args alltys = let ty = arrow_of_args args ety in let msg = Format.asprintf "@[<v>%a is overloaded but none of its types matches:@, @[<hov>%a@]@,Its types are:@,@[<v 2> %a@]@]" F.pp c TypeAssignment.pretty ty (pplist (fun fmt (_,x)-> Format.fprintf fmt "%a" TypeAssignment.pretty x) ", ") alltys in error ~loc msg let error_overloaded_app_tgt ~loc ~ety c = let msg = Format.asprintf "@[<v>%a is overloaded but none of its types matches make it build a term of type @[<hov>%a@]@]" F.pp c TypeAssignment.pretty ety in error ~loc msg let error_not_poly ~loc c ty sk = error ~loc (Format.asprintf "@[<hv>this rule imposes on %a the type@ %a@ is less general than the declared one@ %a@]" F.pp c TypeAssignment.pretty ty TypeAssignment.pretty sk) type ret = TypeAssignment.t MutableOnce.t TypeAssignment.t_ type ret_id = int * TypeAssignment.t MutableOnce.t TypeAssignment.t_ type spilled_phantoms = ScopedTerm.t list let local_type ctx ~loc c : ret_id TypeAssignment.overloading = try TypeAssignment.Single (0, Scope.Map.find c ctx) (* local types have no id, 0 is given by default *) with Not_found -> anomaly ~loc "free variable" type classification = | Simple of { srcs : ret list; tgt : ret } | Variadic of { srcs : ret list; tgt : ret } | Unknown let rec classify_arrow = function | TypeAssignment.Arr(Variadic,x,tgt) -> Variadic { srcs = [x]; tgt } | UVar m when MutableOnce.is_set m -> classify_arrow (TypeAssignment.deref m) | (App _ | Prop | Cons _ | Any | UVar _) as tgt -> Simple { srcs = []; tgt } | TypeAssignment.Arr(NotVariadic,x,xs) -> match classify_arrow xs with | Simple {srcs; tgt } -> Simple { srcs = x :: srcs; tgt } | Unknown -> Unknown | Variadic { srcs; tgt } -> Variadic { srcs = x :: srcs; tgt } let mk_uvar = let i = ref 0 in fun s -> incr i; TypeAssignment.UVar(MutableOnce.make (F.from_string (s ^ string_of_int !i))) let unknown_type_assignment s = TypeAssignment.Val (mk_uvar s) let rec extend l1 l2 = match l1, l2 with | [],_ -> assert false | _, [] -> [] | [x], _:: ys -> x :: extend [x] ys | x::xs, _::ys -> x :: extend [x] ys let is_spill { it } = match it with | Spill _ -> true | _ -> false let rec any_arg_is_spill = function | [] -> false | x :: xs -> is_spill x || any_arg_is_spill xs let silence_linear_warn f = let s = F.show f in let len = String.length s in len > 0 && (s.[0] = '_' || s.[len-1] = '_') let check ~is_rule ~type_abbrevs ~kinds ~types:env ~unknown (t : ScopedTerm.t) ~(exp : TypeAssignment.t) = (* Format.eprintf "============================ checking %a\n" ScopedTerm.pretty t; *) let sigma : (TypeAssignment.t * int * Loc.t) F.Map.t ref = ref F.Map.empty in let unknown_global = ref unknown in let fresh_name = let i = ref 0 in fun () -> incr i; F.from_string ("%dummy"^ string_of_int !i) in (* let set_fresh_id = let i = ref 0 in fun x -> incr i; x := Some !i in *) let rec check (ctx : ret Scope.Map.t) ~loc ~tyctx x ety : spilled_phantoms = (* Format.eprintf "@[<hov 2>checking %a : %a@]\n" ScopedTerm.pretty_ x TypeAssignment.pretty ety; *) match x with | Impl(b,t1,t2) -> check_impl ctx ~loc ~tyctx b t1 t2 ety | Const(Global _ as gid,c) -> check_global ctx ~loc ~tyctx (gid,c) ety | Const(Bound lang,c) -> check_local ctx ~loc ~tyctx (c,lang) ety | CData c -> check_cdata ~loc ~tyctx kinds c ety | Spill(_,{contents = Phantom _}) -> assert false | Spill(sp,info) -> check_spill ctx ~loc ~tyctx sp info ety | App(Global _ as gid,c,x,xs) -> check_app ctx ~loc ~tyctx (c,gid) (global_type env ~loc c) (x::xs) ety | App(Bound lang as gid,c,x,xs) -> check_app ctx ~loc ~tyctx (c,gid) (local_type ctx ~loc (c,lang)) (x::xs) ety | Lam(c,cty,t) -> check_lam ctx ~loc ~tyctx c cty t ety | Discard -> [] | Var(c,args) -> check_app ctx ~loc ~tyctx (c, Bound elpi_language (*hack*)) (uvar_type ~loc c) args ety | Cast(t,ty) -> let ty = TypeAssignment.subst (fun f -> Some (TypeAssignment.UVar(MutableOnce.make f))) @@ check_loc_tye ~type_abbrevs ~kinds F.Set.empty ty in let spills = check_loc ctx ~tyctx:None t ~ety:ty in if unify ty ety then spills else error_bad_ety ~loc ~tyctx ScopedTerm.pretty_ x ty ~ety and resolve_gid id _ = () (*function | Scope.Global x -> x.decl_id <- id | _ -> ()*) and global_type env ~loc c : ret_id TypeAssignment.overloading = try TypeAssignment.fresh_overloaded @@ F.Map.find c env with Not_found -> (* Printf.eprintf "%s\n" F.(show c); assert false; *) try let ty,id,_ = F.Map.find c !unknown_global in Single (id,TypeAssignment.unval ty) with Not_found -> let ty = TypeAssignment.Val (mk_uvar (Format.asprintf "Unknown_type_of_%a_" F.pp c)) in let id = Scope.fresh_type_decl_id () in unknown_global := F.Map.add c (ty,id,loc) !unknown_global; Single (id,TypeAssignment.unval ty) and check_impl ctx ~loc ~tyctx b t1 t2 ety = if not @@ unify (ety) Prop then error_bad_ety ~loc ~tyctx ~ety:Prop ScopedTerm.pretty_ (Impl(b,t1,t2)) (ety) else let lhs, rhs,c (* of => *) = if b then t1,t2,F.implf else t2,t1,F.rimplf in let spills = check_loc ~tyctx:(Some c) ctx rhs ~ety:Prop in let lhs_ty = mk_uvar "Src" in let more_spills = check_loc ~tyctx:None ctx ~ety:lhs_ty lhs in let ety1 = TypeAssignment.Prop in let ety2 = TypeAssignment.App(F.from_string "list",Prop,[]) in if try_unify lhs_ty ety1 then spills @ more_spills (* probably an error if not empty *) else if unify lhs_ty (ety2) then spills @ more_spills (* probably an error if not empty *) else error_bad_ety2 ~tyctx:(Some c) ~loc ~ety1 ~ety2 ScopedTerm.pretty lhs lhs_ty and check_global ctx ~loc ~tyctx (gid,c) ety = match global_type env ~loc c with | Single (id,ty) -> if unify ty ety then (resolve_gid id gid; []) else error_bad_ety ~tyctx ~loc ~ety F.pp c ty | Overloaded l -> if unify_first gid l ety then [] else error_bad_const_ety_l ~tyctx ~loc ~ety c l and check_local ctx ~loc ~tyctx c ety = match local_type ctx ~loc c with | Single (id,ty) -> if unify ty ety then [] else error_bad_ety ~tyctx ~loc ~ety F.pp (fst c) ty | Overloaded _ -> assert false and check_cdata ~loc ~tyctx kinds c ety = let name = F.from_string @@ CData.name c in check_global_exists ~loc name type_abbrevs kinds 0; let ty = TypeAssignment.Cons name in if unify ty ety then [] else error_bad_cdata_ety ~tyctx ~loc c ty ~ety and check_lam ctx ~loc ~tyctx c cty t ety = let name_lang = match c with Some c -> c | None -> fresh_name (), elpi_language in let src = match cty with | None -> mk_uvar "Src" | Some x -> TypeAssignment.subst (fun f -> Some (TypeAssignment.UVar(MutableOnce.make f))) @@ check_loc_tye ~type_abbrevs ~kinds F.Set.empty x in let tgt = mk_uvar "Tgt" in (* let () = Format.eprintf "lam ety %a\n" TypeAssignment.pretty ety in *) if unify (TypeAssignment.Arr(Ast.Structured.NotVariadic,src,tgt)) ety then (* let () = Format.eprintf "add to ctx %a : %a\n" F.pp name TypeAssignment.pretty src in *) check_loc ~tyctx (Scope.Map.add name_lang src ctx) t ~ety:tgt else error_bad_function_ety ~loc ~tyctx ~ety c t and check_spill ctx ~loc ~tyctx sp info ety = let inner_spills = check_spill_conclusion_loc ~tyctx:None ctx sp ~ety:(TypeAssignment.Arr(Ast.Structured.NotVariadic,ety,mk_uvar "Spill")) in assert(inner_spills = []); let phantom_of_spill_ty i ty = { loc; it = Spill(sp,ref (Phantom(i+1))); ty = MutableOnce.create (TypeAssignment.Val ty) } in match classify_arrow (ScopedTerm.type_of sp) with | Simple { srcs; tgt } -> if not @@ unify tgt Prop then error ~loc "only predicates can be spilled"; let spills = srcs in if spills = [] then error ~loc "nothing to spill, the expression lacks no arguments"; let (first_spill) = List.hd spills in if unify first_spill ety then begin info := Main (List.length spills); List.mapi phantom_of_spill_ty @@ List.tl spills end else error_bad_ety ~tyctx ~loc ~ety ScopedTerm.pretty_ (Spill(sp,info)) first_spill | _ -> error ~loc "hard spill" and unify_tgt_ety n ety (_,t) = match classify_arrow t with | Unknown -> true | Simple { srcs; tgt } -> let nsrcs = List.length srcs in if n > nsrcs then false else let rec drop i l = if i = 0 then l else drop (i-1) (List.tl l) in let srcs = drop n srcs in unify_then_undo (arrow_of_tys srcs tgt) ety | Variadic _ -> true (* TODO *) and check_app ctx ~loc ~tyctx (c,cid) cty args ety = match cty with | Overloaded l -> (* Format.eprintf "@[options %a %a %d:@ %a@]\n" F.pp c TypeAssignment.pretty ety (List.length args) (pplist (fun fmt (_,x) -> TypeAssignment.pretty fmt x) "; ") l; *) let l = List.filter (unify_tgt_ety (List.length args) ety) l in begin match l with | [] -> error_overloaded_app_tgt ~loc ~ety c | [ty] -> (* Format.eprintf "1option left: %a\n" TypeAssignment.pretty (snd ty); *) check_app ctx ~loc ~tyctx (c,cid) (Single ty) args ety | l -> (* Format.eprintf "newoptions: %a\n" (pplist (fun fmt (_,x) -> TypeAssignment.pretty fmt x) "; ") l; *) let args = List.concat_map (fun x -> x :: check_loc ~tyctx:None ctx ~ety:(mk_uvar (Format.asprintf "Ety_%a" F.pp c)) x) args in let targs = List.map ScopedTerm.type_of args in check_app_overloaded ctx ~loc (c,cid) ety args targs l l end | Single (id,ty) -> (* Format.eprintf "%a: 1 option: %a\n" F.pp c TypeAssignment.pretty ty; *) let err ty = if args = [] then error_bad_ety ~loc ~tyctx ~ety F.pp c ty (* uvar *) else error_bad_ety ~loc ~tyctx ~ety ScopedTerm.pretty_ (App(Scope.mkGlobal ~escape_ns:true ()(* sucks *),c,List.hd args,List.tl args)) ty in let monodirectional () = (* Format.eprintf "checking app mono %a\n" F.pp c; *) let tgt = check_app_single ctx ~loc (c,cid) ty [] args in if unify tgt ety then (resolve_gid id cid; []) else err tgt in let bidirectional srcs tgt = (* Format.eprintf "checking app bidi %a\n" F.pp c; *) let rec consume args srcs = match args, srcs with | [], srcs -> arrow_of_tys srcs tgt | _ :: args, _ :: srcs -> consume args srcs | _ :: _, [] -> assert false in let rest_tgt = consume args srcs in if unify rest_tgt ety then let _ = check_app_single ctx ~loc (c,cid) ty [] args in (resolve_gid id cid; []) else err rest_tgt in match classify_arrow ty with | Unknown | Variadic _ -> monodirectional () | Simple { srcs; tgt } -> if List.length args > List.length srcs then monodirectional () (* will error *) else if any_arg_is_spill args then monodirectional () else bidirectional srcs tgt (* REDO PROCESSING ONE SRC at a time *) and check_app_overloaded ctx ~loc (c, cid as c_w_id) ety args targs alltys = function | [] -> error_overloaded_app ~loc c args ~ety alltys | (id,t)::ts -> (* Format.eprintf "checking overloaded app %a\n" F.pp c; *) match classify_arrow t with | Unknown -> error ~loc (Format.asprintf "Type too ambiguous to be assigned to the overloaded constant: %s for type %a" (F.show c) TypeAssignment.pretty t) | Simple { srcs; tgt } -> (* Format.eprintf "argsty : %a\n" TypeAssignment.pretty (arrow_of_tys targs ety); *) if try_unify (arrow_of_tys srcs tgt) (arrow_of_tys targs ety) then (resolve_gid id cid;[]) (* TODO: here we should something ? *) else check_app_overloaded ctx ~loc c_w_id ety args targs alltys ts | Variadic { srcs ; tgt } -> let srcs = extend srcs targs in if try_unify (arrow_of_tys srcs tgt) (arrow_of_tys targs ety) then (resolve_gid id cid;[]) (* TODO: here we should something ? *) else check_app_overloaded ctx ~loc c_w_id ety args targs alltys ts and check_app_single ctx ~loc c ty consumed args = match args with | [] -> ty | x :: xs -> (* Format.eprintf "checking app %a against %a\n" ScopedTerm.pretty_ (ScopedTerm.App(snd c, fst c,x,xs)) TypeAssignment.pretty ty; *) match ty with | TypeAssignment.Arr(Variadic,s,t) -> let xs = check_loc_if_not_phantom ~tyctx:(Some (fst c)) ctx x ~ety:s @ xs in if xs = [] then t else check_app_single ctx ~loc c ty (x::consumed) xs | Arr(NotVariadic,s,t) -> let xs = check_loc_if_not_phantom ~tyctx:(Some (fst c)) ctx x ~ety:s @ xs in check_app_single ctx ~loc c t (x::consumed) xs | Any -> check_app_single ctx ~loc c ty (x::consumed) xs | UVar m when MutableOnce.is_set m -> check_app_single ctx ~loc c (TypeAssignment.deref m) consumed (x :: xs) | UVar m -> let s = mk_uvar "Src" in let t = mk_uvar "Tgt" in let _ = unify ty (TypeAssignment.Arr(Ast.Structured.NotVariadic,s,t)) in check_app_single ctx ~loc c ty consumed (x :: xs) | Cons a when F.Map.mem a type_abbrevs -> let ty = TypeAssignment.apply (fst @@ F.Map.find a type_abbrevs) [] in check_app_single ctx ~loc c ty consumed args | App(a,x,xs) when F.Map.mem a type_abbrevs -> let ty = TypeAssignment.apply (fst @@ F.Map.find a type_abbrevs) (x::xs) in check_app_single ctx ~loc c ty consumed args | _ -> error_not_a_function ~loc:x.loc (fst c) ty (List.rev consumed) x (* TODO: trim loc up to x *) and check_loc ~tyctx ctx { loc; it; ty } ~ety : spilled_phantoms = (* if MutableOnce.is_set ty then [] else *) begin (* assert (not @@ MutableOnce.is_set ty); *) let extra_spill = check ~tyctx ctx ~loc it ety in if not @@ MutableOnce.is_set ty then MutableOnce.set ty (Val ety); extra_spill end and check_loc_if_not_phantom ~tyctx ctx x ~ety : spilled_phantoms = match x.it with | Spill(_,{ contents = Phantom _}) -> [] | _ -> check_loc ~tyctx ctx x ~ety and check_spill_conclusion_loc ~tyctx ctx { loc; it; ty } ~ety : spilled_phantoms = (* A spill can be duplicate by a macro for example *) let already_typed = MutableOnce.is_set ty in let extra_spill = check_spill_conclusion ~tyctx ctx ~loc it ety in if not already_typed then MutableOnce.set ty (Val ety); extra_spill (* This descent to find the spilled term is a bit ad hoc, since it inlines => and , typing... but leaves the rest of the code clean *) and check_spill_conclusion ~tyctx ctx ~loc it ety = match it with | Impl(true,x,y) -> let lhs = mk_uvar "LHS" in let spills = check_loc ~tyctx ctx x ~ety:lhs in if spills <> [] then error ~loc "Hard spill"; if try_unify lhs Prop || try_unify lhs (App(F.from_string "list",Prop,[])) then check_spill_conclusion_loc ~tyctx ctx y ~ety else error ~loc "Bad impl in spill" | App(Global _ as g,c,x,xs) when F.equal c F.andf -> let spills = check_loc ~tyctx ctx x ~ety:Prop in if spills <> [] then error ~loc "Hard spill"; begin match xs with | [] -> assert false | [x] -> check_loc ~tyctx ctx x ~ety | x::xs -> check_spill_conclusion ~tyctx ctx ~loc (App(g,c,x,xs)) ety end | _ -> check ~tyctx ctx ~loc it ety and check_matches_poly_skema_loc ~unknown { loc; it } = let c, args = let rec head it = match it with | App(Global _,f,{ it = Lam(_,_,x) },[]) when F.equal F.pif f -> head x.it | Impl(false,{ it = App(Global _,c',x,xs) },_) -> c', x :: xs | Impl(false,{ it = Const(Global _,c') },_) -> c', [] | App(Global _,c,x,xs) -> c, x :: xs | Const(Global _,c) -> c, [] | _ -> (* Format.eprintf "%a" ScopedTerm.pretty_ it; *) assert false in head it in (* Format.eprintf "Checking %a\n" F.pp c; *) match F.Map.find c env with | Single (_id,Ty _) -> () (* TODO: Should use id? *) | Single (_id, Lam _ as sk) -> check_matches_poly_skema ~loc ~pat:(TypeAssignment.fresh sk) c (arrow_of_args args Prop) (* TODO: should use id? *) | Overloaded _ -> () | exception Not_found -> assert(F.Map.mem c unknown) and check_matches_poly_skema ~loc ~pat c ty = if try_matching ~pat ty then () else error_not_poly ~loc c ty (fst pat |> snd) and try_unify x y = let vx = TypeAssignment.vars_of (Val x) in let vy = TypeAssignment.vars_of (Val y) in let b = unify x y in if not b then (undo vx; undo vy); b and unify_then_undo x y = let vx = TypeAssignment.vars_of (Val x) in let vy = TypeAssignment.vars_of (Val y) in let b = unify x y in undo vx; undo vy; b and unify_first gid l ety = let vars = TypeAssignment.vars_of (Val ety) in let rec aux = function | [] -> false | (id, x)::xs -> if unify x ety then (resolve_gid id gid; true) else (undo vars; aux xs) in aux l and undo = function | [] -> () | m :: ms -> MutableOnce.unset m; undo ms and uvar_type ~loc c = try let ty, nocc, loc = F.Map.find c !sigma in sigma := F.Map.add c (ty,nocc+1,loc) !sigma; Single (0, TypeAssignment.unval @@ ty) (* TODO: not sure of this... *) with Not_found -> let ty = TypeAssignment.UVar (MutableOnce.make c) in sigma := F.Map.add c (TypeAssignment.Val ty,1,loc) !sigma; Single (0, ty) (* TODO: not sure of this... *) and unif ~matching t1 t2 = (* Format.eprintf "%a = %a\n" TypeAssignment.pretty t1 TypeAssignment.pretty t2; *) let open TypeAssignment in match t1, t2 with | Any, _ -> true | _, Any -> true | UVar m, _ when MutableOnce.is_set m -> unif ~matching (TypeAssignment.deref m) t2 | _, UVar m when MutableOnce.is_set m -> unif ~matching t1 (TypeAssignment.deref m) | App(c1,x,xs), App(c2,y,ys) when F.equal c1 c2 -> unif ~matching x y && Util.for_all2 (unif ~matching) xs ys | Cons c1, Cons c2 when F.equal c1 c2 -> true | Prop, Prop -> true | Arr(b1,s1,t1), Arr(b2,s2,t2) -> b1 == b2 && unif ~matching s1 s2 && unif ~matching t1 t2 | Arr(Variadic,_,t), _ -> unif ~matching t t2 | _, Arr(Variadic,_,t) -> unif ~matching t1 t | UVar m, UVar n when matching -> assign m t2 | UVar m, _ when not matching -> assign m t2 | _, UVar m -> assign m t1 | Cons c, _ when F.Map.mem c type_abbrevs -> let t1 = apply (fst @@ F.Map.find c type_abbrevs) [] in unif ~matching t1 t2 | _, Cons c when F.Map.mem c type_abbrevs -> let t2 = apply (fst @@ F.Map.find c type_abbrevs) [] in unif ~matching t1 t2 | App(c,x,xs), _ when F.Map.mem c type_abbrevs -> let t1 = apply (fst @@ F.Map.find c type_abbrevs) (x::xs) in unif ~matching t1 t2 | _, App(c,x,xs) when F.Map.mem c type_abbrevs -> let t2 = apply (fst @@ F.Map.find c type_abbrevs) (x::xs) in unif ~matching t1 t2 | _,_ -> false and unify x (y: TypeAssignment.t MutableOnce.t TypeAssignment.t_) = unif ~matching:false x y and try_matching ~pat:((_,x),vars) y = let vars = F.Map.bindings vars |> List.map snd |> List.map cell_of in let deref x = cell_of (TypeAssignment.deref x) in if unif ~matching:true x y then if disjoint (List.map deref vars) then true else (undo vars; false) else (undo vars; false) and cell_of = function | TypeAssignment.UVar x -> x | _ -> assert false and disjoint = function | [] -> true | x :: xs -> not (List.exists (fun y -> same_var y (TypeAssignment.UVar x)) xs) && disjoint xs and assign m t = same_var m t || (oc m t && ((*Format.eprintf "%a := %a\n" MutableOnce.(pp TypeAssignment.pp) m TypeAssignment.(pp_t_ MutableOnce.(pp TypeAssignment.pp)) t;*)TypeAssignment.set m t; true)) and same_var m = function | UVar n when n == m -> true | UVar n when MutableOnce.is_set n -> same_var m (TypeAssignment.deref n) | _ -> false and oc m = function | Prop -> true | Arr(_,x,y) -> oc m x && oc m y | App(_,x,xs) -> List.for_all (oc m) (x::xs) | Any -> true | Cons _ -> true | UVar n when m == n -> false | UVar n when MutableOnce.is_set n -> oc m (TypeAssignment.deref n) | UVar _ -> true in (* this is wrong, since the same unit may be checked against different contexts *) (* if MutableOnce.is_set t.ty then !unknown_global else *) let spills = check_loc ~tyctx:None Scope.Map.empty t ~ety:(TypeAssignment.unval exp) in if is_rule then check_matches_poly_skema_loc ~unknown:!unknown_global t; if spills <> [] then error ~loc:t.loc "cannot spill in head"; F.Map.iter (fun k (_,n,loc) -> if n = 1 && not @@ silence_linear_warn k then warn ~loc (Format.asprintf "%a is linear: name it _%a (discard) or %a_ (fresh variable)" F.pp k F.pp k F.pp k)) !sigma; !unknown_global let check1_undeclared w f (t, id, loc) = match TypeAssignment.is_monomorphic t with | None -> error ~loc Format.(asprintf "@[Unable to infer a closed type for %a:@ %a@]" F.pp f TypeAssignment.pretty (TypeAssignment.unval t)) | Some ty -> if not @@ Re.Str.(string_match (regexp "^\\(.*aux[0-9']*\\|main\\)$") (F.show f) 0) then w := Format.((f, loc), asprintf "type %a %a." F.pp f TypeAssignment.pretty (TypeAssignment.unval t)) :: !w; TypeAssignment.Single (id, ty) let check_undeclared ~unknown = let w = ref [] in let env = F.Map.mapi (check1_undeclared w) unknown in if !w <> [] then begin let undeclared, types = List.split !w in warn Format.(asprintf "@[<v>Undeclared globals:@ @[<v>%a@].@ Please add the following text to your program:@\n%a@]" (pplist (fun fmt (f,loc) -> Format.fprintf fmt "- %a %a" Loc.pp loc F.pp f) ", ") undeclared (pplist pp_print_string "") types); end; env (* let check ~type_abbrevs a b c = try check ~type_abbrevs a b c with | CompileError(_,"Unknown global: %spill") -> Printf.eprintf "SPILLING"; exit 1 | CompileError(_,s) when Re.Str.(string_match (regexp "Unknown global: @")) s 0 -> Printf.eprintf "MACRO"; exit 1 | CompileError(loc,msg) -> Format.eprintf "Ignoring type error: %a %s\n" (Util.pp_option Loc.pp) loc msg; TypeAssignment.(Val Prop) *)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>