comparison src/elaborate.sml @ 12:d89477f07c1e

Fun with records
author Adam Chlipala <adamc@hcoop.net>
date Fri, 28 Mar 2008 17:34:57 -0400
parents e97c6d335869
children 6049e2193bf2
comparison
equal deleted inserted replaced
11:e97c6d335869 12:d89477f07c1e
134 134
135 val dummy = ErrorMsg.dummySpan 135 val dummy = ErrorMsg.dummySpan
136 136
137 val ktype = (L'.KType, dummy) 137 val ktype = (L'.KType, dummy)
138 val kname = (L'.KName, dummy) 138 val kname = (L'.KName, dummy)
139 val ktype_record = (L'.KRecord ktype, dummy)
139 140
140 val cerror = (L'.CError, dummy) 141 val cerror = (L'.CError, dummy)
141 val kerror = (L'.KError, dummy) 142 val kerror = (L'.KError, dummy)
142 val eerror = (L'.EError, dummy) 143 val eerror = (L'.EError, dummy)
143 144
311 datatype cunify_error = 312 datatype cunify_error =
312 CKind of L'.kind * L'.kind * kunify_error 313 CKind of L'.kind * L'.kind * kunify_error
313 | COccursCheckFailed of L'.con * L'.con 314 | COccursCheckFailed of L'.con * L'.con
314 | CIncompatible of L'.con * L'.con 315 | CIncompatible of L'.con * L'.con
315 | CExplicitness of L'.con * L'.con 316 | CExplicitness of L'.con * L'.con
317 | CKindof of L'.con
318 | CRecordFailure
316 319
317 exception CUnify' of cunify_error 320 exception CUnify' of cunify_error
318 321
319 fun cunifyError env err = 322 fun cunifyError env err =
320 case err of 323 case err of
333 ("Con 2", p_con env c2)] 336 ("Con 2", p_con env c2)]
334 | CExplicitness (c1, c2) => 337 | CExplicitness (c1, c2) =>
335 eprefaces "Differing constructor function explicitness" 338 eprefaces "Differing constructor function explicitness"
336 [("Con 1", p_con env c1), 339 [("Con 1", p_con env c1),
337 ("Con 2", p_con env c2)] 340 ("Con 2", p_con env c2)]
338 341 | CKindof c =>
339 fun hnormCon env (cAll as (c, _)) = 342 eprefaces "Kind unification variable blocks kindof calculation"
343 [("Con", p_con env c)]
344 | CRecordFailure =>
345 eprefaces "Can't unify record constructors" []
346
347 exception SynUnif
348
349 val liftConInCon =
350 U.Con.mapB {kind = fn k => k,
351 con = fn bound => fn c =>
352 case c of
353 L'.CRel xn =>
354 if xn < bound then
355 c
356 else
357 L'.CRel (xn + 1)
358 | L'.CUnif _ => raise SynUnif
359 | _ => c,
360 bind = fn (bound, U.Con.Rel _) => bound + 1
361 | (bound, _) => bound}
362
363 val subConInCon =
364 U.Con.mapB {kind = fn k => k,
365 con = fn (xn, rep) => fn c =>
366 case c of
367 L'.CRel xn' =>
368 if xn = xn' then
369 #1 rep
370 else
371 c
372 | L'.CUnif _ => raise SynUnif
373 | _ => c,
374 bind = fn ((xn, rep), U.Con.Rel _) => (xn+1, liftConInCon 0 rep)
375 | (ctx, _) => ctx}
376
377 type record_summary = {
378 fields : (L'.con * L'.con) list,
379 unifs : (L'.con * L'.con option ref) list,
380 others : L'.con list
381 }
382
383 fun summaryToCon {fields, unifs, others} =
384 let
385 val c = (L'.CRecord (ktype, []), dummy)
386 val c = List.foldr (fn (c', c) => (L'.CConcat (c', c), dummy)) c others
387 val c = List.foldr (fn ((c', _), c) => (L'.CConcat (c', c), dummy)) c unifs
388 in
389 (L'.CConcat ((L'.CRecord (ktype, fields), dummy), c), dummy)
390 end
391
392 fun p_summary env s = p_con env (summaryToCon s)
393
394 exception CUnify of L'.con * L'.con * cunify_error
395
396 fun hnormKind (kAll as (k, _)) =
397 case k of
398 L'.KUnif (_, ref (SOME k)) => hnormKind k
399 | _ => kAll
400
401 fun kindof env (c, loc) =
402 case c of
403 L'.TFun _ => ktype
404 | L'.TCFun _ => ktype
405 | L'.TRecord _ => ktype
406
407 | L'.CRel xn => #2 (E.lookupCRel env xn)
408 | L'.CNamed xn => #2 (E.lookupCNamed env xn)
409 | L'.CApp (c, _) =>
410 (case #1 (hnormKind (kindof env c)) of
411 L'.KArrow (_, k) => k
412 | L'.KError => kerror
413 | _ => raise CUnify' (CKindof c))
414 | L'.CAbs (x, k, c) => (L'.KArrow (k, kindof (E.pushCRel env x k) c), loc)
415
416 | L'.CName _ => kname
417
418 | L'.CRecord (k, _) => (L'.KRecord k, loc)
419 | L'.CConcat (c, _) => kindof env c
420
421 | L'.CError => kerror
422 | L'.CUnif (k, _, _) => k
423
424 fun unifyRecordCons env (c1, c2) =
425 let
426 val k1 = kindof env c1
427 val k2 = kindof env c2
428 in
429 unifyKinds k1 k2;
430 unifySummaries env (k1, recordSummary env c1, recordSummary env c2)
431 end
432
433 and recordSummary env c : record_summary =
434 case hnormCon env c of
435 (L'.CRecord (_, xcs), _) => {fields = xcs, unifs = [], others = []}
436 | (L'.CConcat (c1, c2), _) =>
437 let
438 val s1 = recordSummary env c1
439 val s2 = recordSummary env c2
440 in
441 {fields = #fields s1 @ #fields s2,
442 unifs = #unifs s1 @ #unifs s2,
443 others = #others s1 @ #others s2}
444 end
445 | (L'.CUnif (_, _, ref (SOME c)), _) => recordSummary env c
446 | c' as (L'.CUnif (_, _, r), _) => {fields = [], unifs = [(c', r)], others = []}
447 | c' => {fields = [], unifs = [], others = [c']}
448
449 and consEq env (c1, c2) =
450 (unifyCons env c1 c2;
451 true)
452 handle CUnify _ => false
453
454 and unifySummaries env (k, s1 : record_summary, s2 : record_summary) =
455 let
456 val () = eprefaces "Summaries" [("#1", p_summary env s1),
457 ("#2", p_summary env s2)]
458
459 fun eatMatching p (ls1, ls2) =
460 let
461 fun em (ls1, ls2, passed1) =
462 case ls1 of
463 [] => (rev passed1, ls2)
464 | h1 :: t1 =>
465 let
466 fun search (ls2', passed2) =
467 case ls2' of
468 [] => em (t1, ls2, h1 :: passed1)
469 | h2 :: t2 =>
470 if p (h1, h2) then
471 em (t1, List.revAppend (passed2, t2), passed1)
472 else
473 search (t2, h2 :: passed2)
474 in
475 search (ls2, [])
476 end
477 in
478 em (ls1, ls2, [])
479 end
480
481 val (fs1, fs2) = eatMatching (fn ((x1, c1), (x2, c2)) =>
482 if consEq env (x1, x2) then
483 (unifyCons env c1 c2;
484 true)
485 else
486 false) (#fields s1, #fields s2)
487 val () = eprefaces "Summaries2" [("#1", p_summary env {fields = fs1, unifs = #unifs s1, others = #others s1}),
488 ("#2", p_summary env {fields = fs2, unifs = #unifs s2, others = #others s2})]
489 val (unifs1, unifs2) = eatMatching (fn ((_, r1), (_, r2)) => r1 = r2) (#unifs s1, #unifs s2)
490 val (others1, others2) = eatMatching (consEq env) (#others s1, #others s2)
491
492 fun unifFields (fs, others, unifs) =
493 case (fs, others, unifs) of
494 ([], [], _) => ([], [], unifs)
495 | (_, _, []) => (fs, others, [])
496 | (_, _, (_, r) :: rest) =>
497 let
498 val r' = ref NONE
499 val cr' = (L'.CUnif (k, "recd", r'), dummy)
500
501 val prefix = case (fs, others) of
502 ([], other :: others) =>
503 List.foldl (fn (other, c) =>
504 (L'.CConcat (c, other), dummy))
505 other others
506 | (fs, []) =>
507 (L'.CRecord (k, fs), dummy)
508 | (fs, others) =>
509 List.foldl (fn (other, c) =>
510 (L'.CConcat (c, other), dummy))
511 (L'.CRecord (k, fs), dummy) others
512 in
513 r := SOME (L'.CConcat (prefix, cr'), dummy);
514 ([], [], (cr', r') :: rest)
515 end
516
517 val (fs1, others1, unifs2) = unifFields (fs1, others1, unifs2)
518 val (fs2, others2, unifs1) = unifFields (fs2, others2, unifs1)
519
520 val clear1 = case (fs1, others1) of
521 ([], []) => true
522 | _ => false
523 val clear2 = case (fs2, others2) of
524 ([], []) => true
525 | _ => false
526 val empty = (L'.CRecord (k, []), dummy)
527 fun pairOffUnifs (unifs1, unifs2) =
528 case (unifs1, unifs2) of
529 ([], _) =>
530 if clear1 then
531 List.app (fn (_, r) => r := SOME empty) unifs2
532 else
533 raise CUnify' CRecordFailure
534 | (_, []) =>
535 if clear2 then
536 List.app (fn (_, r) => r := SOME empty) unifs1
537 else
538 raise CUnify' CRecordFailure
539 | ((c1, _) :: rest1, (_, r2) :: rest2) =>
540 (r2 := SOME c1;
541 pairOffUnifs (rest1, rest2))
542 in
543 pairOffUnifs (unifs1, unifs2)
544 end
545
546 and hnormCon env (cAll as (c, _)) =
340 case c of 547 case c of
341 L'.CUnif (_, _, ref (SOME c)) => hnormCon env c 548 L'.CUnif (_, _, ref (SOME c)) => hnormCon env c
342 549
343 | L'.CNamed xn => 550 | L'.CNamed xn =>
344 (case E.lookupCNamed env xn of 551 (case E.lookupCNamed env xn of
345 (_, _, SOME c') => hnormCon env c' 552 (_, _, SOME c') => hnormCon env c'
346 | _ => cAll) 553 | _ => cAll)
347 554
555 | L'.CApp (c1, c2) =>
556 (case hnormCon env c1 of
557 (L'.CAbs (_, _, cb), _) =>
558 ((hnormCon env (subConInCon (0, c2) cb))
559 handle SynUnif => cAll)
560 | _ => cAll)
561
562 | L'.CConcat (c1, c2) =>
563 (case (hnormCon env c1, hnormCon env c2) of
564 ((L'.CRecord (k, xcs1), loc), (L'.CRecord (_, xcs2), _)) =>
565 (L'.CRecord (k, xcs1 @ xcs2), loc)
566 | _ => cAll)
567
348 | _ => cAll 568 | _ => cAll
349 569
350 fun unifyCons' env c1 c2 = 570 and unifyCons' env c1 c2 =
351 unifyCons'' env (hnormCon env c1) (hnormCon env c2) 571 unifyCons'' env (hnormCon env c1) (hnormCon env c2)
352 572
353 and unifyCons'' env (c1All as (c1, _)) (c2All as (c2, _)) = 573 and unifyCons'' env (c1All as (c1, _)) (c2All as (c2, _)) =
354 let 574 let
355 fun err f = raise CUnify' (f (c1All, c2All)) 575 fun err f = raise CUnify' (f (c1All, c2All))
576
577 fun isRecord () = unifyRecordCons env (c1All, c2All)
356 in 578 in
357 case (c1, c2) of 579 case (c1, c2) of
358 (L'.TFun (d1, r1), L'.TFun (d2, r2)) => 580 (L'.TFun (d1, r1), L'.TFun (d2, r2)) =>
359 (unifyCons' env d1 d2; 581 (unifyCons' env d1 d2;
360 unifyCons' env r1 r2) 582 unifyCons' env r1 r2)
388 if n1 = n2 then 610 if n1 = n2 then
389 () 611 ()
390 else 612 else
391 err CIncompatible 613 err CIncompatible
392 614
393 | (L'.CRecord (k1, rs1), L'.CRecord (k2, rs2)) =>
394 (unifyKinds k1 k2;
395 ((ListPair.appEq (fn ((n1, v1), (n2, v2)) =>
396 (unifyCons' env n1 n2;
397 unifyCons' env v1 v2)) (rs1, rs2))
398 handle ListPair.UnequalLengths => err CIncompatible))
399 | (L'.CConcat (d1, r1), L'.CConcat (d2, r2)) =>
400 (unifyCons' env d1 d2;
401 unifyCons' env r1 r2)
402
403
404 | (L'.CError, _) => () 615 | (L'.CError, _) => ()
405 | (_, L'.CError) => () 616 | (_, L'.CError) => ()
406 617
407 | (L'.CUnif (_, _, ref (SOME c1All)), _) => unifyCons' env c1All c2All 618 | (L'.CUnif (_, _, ref (SOME c1All)), _) => unifyCons' env c1All c2All
408 | (_, L'.CUnif (_, _, ref (SOME c2All))) => unifyCons' env c1All c2All 619 | (_, L'.CUnif (_, _, ref (SOME c2All))) => unifyCons' env c1All c2All
423 if occursCon r c1All then 634 if occursCon r c1All then
424 err COccursCheckFailed 635 err COccursCheckFailed
425 else 636 else
426 r := SOME c1All 637 r := SOME c1All
427 638
639 | (L'.CRecord _, _) => isRecord ()
640 | (_, L'.CRecord _) => isRecord ()
641 | (L'.CConcat _, _) => isRecord ()
642 | (_, L'.CConcat _) => isRecord ()
643
428 | _ => err CIncompatible 644 | _ => err CIncompatible
429 end 645 end
430 646
431 exception CUnify of L'.con * L'.con * cunify_error 647 and unifyCons env c1 c2 =
432
433 fun unifyCons env c1 c2 =
434 unifyCons' env c1 c2 648 unifyCons' env c1 c2
435 handle CUnify' err => raise CUnify (c1, c2, err) 649 handle CUnify' err => raise CUnify (c1, c2, err)
436 | KUnify args => raise CUnify (c1, c2, CKind args) 650 | KUnify args => raise CUnify (c1, c2, CKind args)
437 651
438 datatype exp_error = 652 datatype exp_error =
462 fun checkCon env e c1 c2 = 676 fun checkCon env e c1 c2 =
463 unifyCons env c1 c2 677 unifyCons env c1 c2
464 handle CUnify (c1, c2, err) => 678 handle CUnify (c1, c2, err) =>
465 expError env (Unify (e, c1, c2, err)) 679 expError env (Unify (e, c1, c2, err))
466 680
467 exception SynUnif
468
469 val liftConInCon =
470 U.Con.mapB {kind = fn k => k,
471 con = fn bound => fn c =>
472 case c of
473 L'.CRel xn =>
474 if xn < bound then
475 c
476 else
477 L'.CRel (xn + 1)
478 | L'.CUnif _ => raise SynUnif
479 | _ => c,
480 bind = fn (bound, U.Con.Rel _) => bound + 1
481 | (bound, _) => bound}
482
483 val subConInCon =
484 U.Con.mapB {kind = fn k => k,
485 con = fn (xn, rep) => fn c =>
486 case c of
487 L'.CRel xn' =>
488 if xn = xn' then
489 #1 rep
490 else
491 c
492 | L'.CUnif _ => raise SynUnif
493 | _ => c,
494 bind = fn ((xn, rep), U.Con.Rel _) => (xn+1, liftConInCon 0 rep)
495 | (ctx, _) => ctx}
496
497 fun elabExp env (e, loc) = 681 fun elabExp env (e, loc) =
498 case e of 682 case e of
499 L.EAnnot (e, t) => 683 L.EAnnot (e, t) =>
500 let 684 let
501 val (e', et) = elabExp env e 685 val (e', et) = elabExp env e
573 val (e', et) = elabExp (E.pushCRel env x k') e 757 val (e', et) = elabExp (E.pushCRel env x k') e
574 in 758 in
575 ((L'.ECAbs (expl', x, k', e'), loc), 759 ((L'.ECAbs (expl', x, k', e'), loc),
576 (L'.TCFun (expl', x, k', et), loc)) 760 (L'.TCFun (expl', x, k', et), loc))
577 end 761 end
762
763 | L.ERecord xes =>
764 let
765 val xes' = map (fn (x, e) =>
766 let
767 val (x', xk) = elabCon env x
768 val (e', et) = elabExp env e
769 in
770 checkKind env x' xk kname;
771 (x', e', et)
772 end) xes
773 in
774 ((L'.ERecord (map (fn (x', e', _) => (x', e')) xes'), loc),
775 (L'.TRecord (L'.CRecord (ktype, map (fn (x', _, et) => (x', et)) xes'), loc), loc))
776 end
777
778 | L.EField (e, c) =>
779 let
780 val (e', et) = elabExp env e
781 val (c', ck) = elabCon env c
782
783 val ft = cunif ktype
784 val rest = cunif ktype_record
785 in
786 checkKind env c' ck kname;
787 checkCon env e' et (L'.TRecord (L'.CConcat ((L'.CRecord (ktype, [(c', ft)]), loc), rest), loc), loc);
788 ((L'.EField (e', c', {field = ft, rest = rest}), loc), ft)
789 end
790
578 791
579 datatype decl_error = 792 datatype decl_error =
580 KunifsRemainKind of ErrorMsg.span * L'.kind 793 KunifsRemainKind of ErrorMsg.span * L'.kind
581 | KunifsRemainCon of ErrorMsg.span * L'.con 794 | KunifsRemainCon of ErrorMsg.span * L'.con
582 | KunifsRemainExp of ErrorMsg.span * L'.exp 795 | KunifsRemainExp of ErrorMsg.span * L'.exp
601 (ErrorMsg.errorAt loc "Some constructor unification variables are undetermined in expression"; 814 (ErrorMsg.errorAt loc "Some constructor unification variables are undetermined in expression";
602 eprefaces' [("Expression", p_exp env e)]) 815 eprefaces' [("Expression", p_exp env e)])
603 816
604 fun elabDecl env (d, loc) = 817 fun elabDecl env (d, loc) =
605 (resetKunif (); 818 (resetKunif ();
819 resetCunif ();
606 case d of 820 case d of
607 L.DCon (x, ko, c) => 821 L.DCon (x, ko, c) =>
608 let 822 let
609 val k' = case ko of 823 val k' = case ko of
610 NONE => kunif () 824 NONE => kunif ()