| 20 |
|
|
| 21 |
module S = struct type t = string let compare = compare end |
module S = struct type t = string let compare = compare end |
| 22 |
module TypeEnv = Map.Make(S) |
module TypeEnv = Map.Make(S) |
|
module Env = Map.Make(Id) |
|
|
|
|
| 23 |
|
|
| 24 |
exception NonExhaustive of Types.descr |
exception NonExhaustive of Types.descr |
| 25 |
exception Constraint of Types.descr * Types.descr * string |
exception Constraint of Types.descr * Types.descr |
| 26 |
exception ShouldHave of Types.descr * string |
exception ShouldHave of Types.descr * string |
| 27 |
exception ShouldHave2 of Types.descr * string * Types.descr |
exception ShouldHave2 of Types.descr * string * Types.descr |
| 28 |
exception WrongLabel of Types.descr * label |
exception WrongLabel of Types.descr * label |
| 29 |
exception UnboundId of id |
exception UnboundId of id |
| 30 |
|
exception Error of string |
| 31 |
|
|
| 32 |
let raise_loc loc exn = raise (Location (loc,exn)) |
let raise_loc loc exn = raise (Location (loc,exn)) |
| 33 |
|
let error loc msg = raise_loc loc (Error msg) |
| 34 |
|
|
| 35 |
|
|
| 36 |
(* Eliminate Recursion, propagate Sequence Capture Variables *) |
(* Eliminate Recursion, propagate Sequence Capture Variables *) |
| 491 |
|
|
| 492 |
let all_branches = ref [] |
let all_branches = ref [] |
| 493 |
|
|
|
(* IDEA: introduce a node Loc in the AST to override nolocs |
|
|
in sub-expressions *) |
|
|
|
|
| 494 |
let exp loc fv e = |
let exp loc fv e = |
| 495 |
fv, |
fv, |
| 496 |
{ Typed.exp_loc = loc; |
{ Typed.exp_loc = loc; |
| 555 |
| Op (op,le) -> |
| Op (op,le) -> |
| 556 |
let (fvs,ltes) = List.split (List.map (expr loc) le) in |
let (fvs,ltes) = List.split (List.map (expr loc) le) in |
| 557 |
let fv = List.fold_left Fv.cup Fv.empty fvs in |
let fv = List.fold_left Fv.cup Fv.empty fvs in |
| 558 |
exp loc fv (Typed.Op (op,ltes)) |
(try |
| 559 |
|
(match (ltes,Typed.find_op op) with |
| 560 |
|
| [e], `Unary op -> exp loc fv (Typed.UnaryOp (op, e)) |
| 561 |
|
| [e1;e2], `Binary op -> exp loc fv (Typed.BinaryOp (op, e1,e2)) |
| 562 |
|
| _ -> assert false) |
| 563 |
|
with Not_found -> assert false) |
| 564 |
|
|
| 565 |
| Match (e,b) -> |
| Match (e,b) -> |
| 566 |
let (fv1,e) = expr loc e |
let (fv1,e) = expr loc e |
| 567 |
and (fv2,b) = branches b in |
and (fv2,b) = branches b in |
| 568 |
exp loc (Fv.cup fv1 fv2) (Typed.Match (e, b)) |
exp loc (Fv.cup fv1 fv2) (Typed.Match (e, b)) |
| 569 |
| Map (def,e,b) -> |
| Map (e,b) -> |
| 570 |
let (fv1,e) = expr loc e |
let (fv1,e) = expr loc e |
| 571 |
and (fv2,b) = branches b in |
and (fv2,b) = branches b in |
| 572 |
exp loc (Fv.cup fv1 fv2) (Typed.Map (def,e, b)) |
exp loc (Fv.cup fv1 fv2) (Typed.Map (e, b)) |
| 573 |
|
| Transform (e,b) -> |
| 574 |
|
let (fv1,e) = expr loc e |
| 575 |
|
and (fv2,b) = branches b in |
| 576 |
|
exp loc (Fv.cup fv1 fv2) (Typed.Transform (e, b)) |
| 577 |
| Xtrans (e,b) -> |
| Xtrans (e,b) -> |
| 578 |
let (fv1,e) = expr loc e |
let (fv1,e) = expr loc e |
| 579 |
and (fv2,b) = branches b in |
and (fv2,b) = branches b in |
| 622 |
|
|
| 623 |
(* III. Type-checks *) |
(* III. Type-checks *) |
| 624 |
|
|
|
let int_cup_record = Types.cup Types.Int.any Types.Record.any |
|
|
|
|
|
|
|
| 625 |
type env = Types.descr Env.t |
type env = Types.descr Env.t |
| 626 |
|
|
| 627 |
open Typed |
open Typed |
| 628 |
|
|
| 629 |
|
let require loc t s = |
| 630 |
|
if not (Types.subtype t s) then raise_loc loc (Constraint (t, s)) |
| 631 |
|
|
| 632 |
|
let check loc t s = |
| 633 |
|
require loc t s; t |
| 634 |
|
|
| 635 |
let check loc t s msg = |
let should_have loc constr s = |
| 636 |
if not (Types.subtype t s) then raise_loc loc (Constraint (t, s, msg)) |
raise_loc loc (ShouldHave (constr,s)) |
| 637 |
|
|
| 638 |
|
let flatten loc arg constr precise = |
| 639 |
|
let constr' = Sequence.star |
| 640 |
|
(Sequence.approx (Types.cap Sequence.any constr)) in |
| 641 |
|
let sconstr' = Sequence.star constr' in |
| 642 |
|
let exact = Types.subtype constr' constr in |
| 643 |
|
if exact then |
| 644 |
|
let t = arg sconstr' precise in |
| 645 |
|
if precise then Sequence.flatten t else constr |
| 646 |
|
else |
| 647 |
|
let t = arg sconstr' true in |
| 648 |
|
Sequence.flatten t |
| 649 |
|
|
| 650 |
let rec type_check env e constr precise = |
let rec type_check env e constr precise = |
|
(* Format.fprintf Format.std_formatter "constr=%a precise=%b@\n" |
|
|
Types.Print.print_descr constr precise; |
|
|
*) |
|
| 651 |
let d = type_check' e.exp_loc env e.exp_descr constr precise in |
let d = type_check' e.exp_loc env e.exp_descr constr precise in |
| 652 |
|
let d = if precise then d else constr in |
| 653 |
e.exp_typ <- Types.cup e.exp_typ d; |
e.exp_typ <- Types.cup e.exp_typ d; |
| 654 |
d |
d |
| 655 |
|
|
| 657 |
| Forget (e,t) -> |
| Forget (e,t) -> |
| 658 |
let t = Types.descr t in |
let t = Types.descr t in |
| 659 |
ignore (type_check env e t false); |
ignore (type_check env e t false); |
| 660 |
t |
check loc t constr |
| 661 |
|
|
| 662 |
| Abstraction a -> |
| Abstraction a -> |
| 663 |
let t = |
let t = |
| 664 |
try Types.Arrow.check_strenghten a.fun_typ constr |
try Types.Arrow.check_strenghten a.fun_typ constr |
| 665 |
with Not_found -> |
with Not_found -> |
| 666 |
raise_loc loc |
should_have loc constr |
| 667 |
(ShouldHave |
"but the interface of the abstraction is not compatible" |
|
(constr, "but the interface of the abstraction is not compatible")) |
|
| 668 |
in |
in |
| 669 |
let env = match a.fun_name with |
let env = match a.fun_name with |
| 670 |
| None -> env |
| None -> env |
| 689 |
|
|
| 690 |
| Pair (e1,e2) -> |
| Pair (e1,e2) -> |
| 691 |
type_check_pair loc env e1 e2 constr precise |
type_check_pair loc env e1 e2 constr precise |
| 692 |
|
|
| 693 |
| Xml (e1,e2) -> |
| Xml (e1,e2) -> |
| 694 |
type_check_pair ~kind:`XML loc env e1 e2 constr precise |
type_check_pair ~kind:`XML loc env e1 e2 constr precise |
| 695 |
|
|
| 696 |
| RecordLitt r -> |
| RecordLitt r -> |
| 697 |
(* try to get rid of precise = true for values of fields *) |
type_record loc env r constr precise |
| 698 |
(* also: the use equivalent of need_second to optimize... *) |
|
| 699 |
let precise = true in |
| Map (e,b) -> |
| 700 |
if not (Types.Record.has_record constr) then |
type_map loc env false e b constr precise |
| 701 |
raise_loc loc (ShouldHave (constr,"but it is a record.")); |
|
| 702 |
let (rconstr,res) = |
| Transform (e,b) -> |
| 703 |
List.fold_left |
flatten loc (type_map loc env true e b) constr precise |
|
(fun (rconstr,res) (l,e) -> |
|
|
(* could compute (split l e) once... *) |
|
|
let pi = Types.Record.project_opt rconstr l in |
|
|
if Types.is_empty pi then |
|
|
raise_loc loc |
|
|
(ShouldHave (constr,(Printf.sprintf |
|
|
"Field %s is not allowed here." |
|
|
(U.to_string (LabelPool.value l)) |
|
|
) |
|
|
)); |
|
|
let t = type_check env e pi true in |
|
|
let rconstr = Types.Record.condition rconstr l t in |
|
|
let res = if precise then (l,Types.cons t) :: res else res in |
|
|
(rconstr,res) |
|
|
) (constr, []) (LabelMap.get r) |
|
|
in |
|
|
if not (Types.Record.has_empty_record rconstr) then |
|
|
raise_loc loc |
|
|
(ShouldHave (constr,"More fields should be present")); |
|
|
let t = |
|
|
Types.record' (false, LabelMap.from_list (fun _ _ -> assert false) res) |
|
|
in |
|
|
check loc t constr ""; |
|
|
t |
|
|
(* |
|
|
if precise then |
|
|
Types.record' (false, LabelMap.from_list (fun _ _ -> assert false) res) |
|
|
else constr |
|
|
*) |
|
|
| Map (def,e,b) -> |
|
|
let acc = if def then Sequence.any else Sequence.star b.br_accept in |
|
|
let t = type_check env e acc true in |
|
| 704 |
|
|
|
let constr' = Sequence.approx (Types.cap Sequence.any constr) in |
|
|
let exact = Types.subtype (Sequence.star constr') constr in |
|
|
(* Note: |
|
|
- could be more precise by integrating the decomposition |
|
|
of constr inside Sequence.map. |
|
|
*) |
|
|
let res = |
|
|
Sequence.map |
|
|
(fun t -> |
|
|
let res = |
|
|
type_check_branches loc env t b constr' (precise || (not exact)) in |
|
|
if def && not (Types.subtype t b.br_accept) |
|
|
then Types.cup res Sequence.nil_type |
|
|
else res) |
|
|
t in |
|
|
if not exact then check loc res constr ""; |
|
|
if precise then res else constr |
|
|
| Op ("@", [e1;e2]) -> |
|
|
let constr' = Sequence.star |
|
|
(Sequence.approx (Types.cap Sequence.any constr)) in |
|
|
let exact = Types.subtype constr' constr in |
|
|
if exact then |
|
|
let t1 = type_check env e1 constr' precise |
|
|
and t2 = type_check env e2 constr' precise in |
|
|
if precise then Sequence.concat t1 t2 else constr |
|
|
else |
|
|
(* Note: |
|
|
the knownledge of t1 may makes it useless to |
|
|
check t2 with 'precise' ... *) |
|
|
let t1 = type_check env e1 constr' true |
|
|
and t2 = type_check env e2 constr' true in |
|
|
let res = Sequence.concat t1 t2 in |
|
|
check loc res constr ""; |
|
|
if precise then res else constr |
|
| 705 |
| Apply (e1,e2) -> |
| Apply (e1,e2) -> |
| 706 |
let t1 = type_check env e1 Types.Arrow.any true in |
let t1 = type_check env e1 Types.Arrow.any true in |
| 707 |
let t1 = Types.Arrow.get t1 in |
let t1 = Types.Arrow.get t1 in |
| 713 |
else |
else |
| 714 |
(ignore (type_check env e2 dom false); Types.Arrow.apply_noarg t1) |
(ignore (type_check env e2 dom false); Types.Arrow.apply_noarg t1) |
| 715 |
in |
in |
| 716 |
check loc res constr ""; |
check loc res constr |
| 717 |
res |
|
| 718 |
| Op ("flatten", [e]) -> |
| UnaryOp (o,e) -> |
| 719 |
let constr' = Sequence.star |
let t = o.un_op_typer loc (type_check env e) constr precise in |
| 720 |
(Sequence.approx (Types.cap Sequence.any constr)) in |
check loc t constr |
| 721 |
let sconstr' = Sequence.star constr' in |
|
| 722 |
let exact = Types.subtype constr' constr in |
| BinaryOp (o,e1,e2) -> |
| 723 |
if exact then |
let t = o.bin_op_typer loc (type_check env e1) (type_check env e2) constr precise in |
| 724 |
let t = type_check env e sconstr' precise in |
check loc t constr |
| 725 |
if precise then Sequence.flatten t else constr |
|
| 726 |
else |
| Var s -> |
| 727 |
let t = type_check env e sconstr' true in |
let t = |
| 728 |
let res = Sequence.flatten t in |
try Env.find s env |
| 729 |
check loc res constr ""; |
with Not_found -> raise_loc loc (UnboundId s) in |
| 730 |
if precise then res else constr |
check loc t constr |
| 731 |
| Op ("atom_of", [e]) -> |
|
| 732 |
let t = type_check env e Sequence.string false in |
| Cst c -> |
| 733 |
Types.atom Atoms.any |
check loc (Types.constant c) constr |
| 734 |
| _ -> |
|
| 735 |
let t : Types.descr = compute_type' loc env e in |
| Dot (e,l) -> |
| 736 |
check loc t constr ""; |
let t = type_check env e Types.Record.any true in |
| 737 |
t |
let t = |
| 738 |
|
try (Types.Record.project t l) |
| 739 |
|
with Not_found -> raise_loc loc (WrongLabel(t,l)) |
| 740 |
|
in |
| 741 |
|
check loc t constr |
| 742 |
|
|
| 743 |
|
| RemoveField (e,l) -> |
| 744 |
|
let t = type_check env e Types.Record.any true in |
| 745 |
|
let t = Types.Record.remove_field t l in |
| 746 |
|
check loc t constr |
| 747 |
|
|
| 748 |
|
| Xtrans (e,b) -> |
| 749 |
|
let t = type_check env e Sequence.any true in |
| 750 |
|
let t = |
| 751 |
|
Sequence.map_tree |
| 752 |
|
(fun t -> |
| 753 |
|
let resid = Types.diff t b.br_accept in |
| 754 |
|
let res = type_check_branches loc env t b Sequence.any true in |
| 755 |
|
(res,resid) |
| 756 |
|
) t in |
| 757 |
|
check loc t constr |
| 758 |
|
|
| 759 |
|
|
| 760 |
and type_check_pair ?(kind=`Normal) loc env e1 e2 constr precise = |
and type_check_pair ?(kind=`Normal) loc env e1 e2 constr precise = |
| 761 |
let rects = Types.Product.normal ~kind constr in |
let rects = Types.Product.normal ~kind constr in |
| 762 |
if Types.Product.is_empty rects then |
if Types.Product.is_empty rects then |
| 763 |
(match kind with |
(match kind with |
| 764 |
| `Normal -> raise_loc loc (ShouldHave (constr,"but it is a pair.")) |
| `Normal -> should_have loc constr "but it is a pair" |
| 765 |
| `XML -> raise_loc loc (ShouldHave (constr,"but it is an XML element."))); |
| `XML -> should_have loc constr "but it is an XML element"); |
| 766 |
let need_s = Types.Product.need_second rects in |
let need_s = Types.Product.need_second rects in |
| 767 |
let t1 = type_check env e1 (Types.Product.pi1 rects) (precise || need_s) in |
let t1 = type_check env e1 (Types.Product.pi1 rects) (precise || need_s) in |
| 768 |
let c2 = Types.Product.constraint_on_2 rects t1 in |
let c2 = Types.Product.constraint_on_2 rects t1 in |
| 777 |
else |
else |
| 778 |
constr |
constr |
| 779 |
|
|
| 780 |
|
and type_record loc env r constr precise = |
| 781 |
and compute_type env e = |
(* try to get rid of precise = true for values of fields *) |
| 782 |
type_check env e Types.any true |
(* also: the use equivalent of need_second to optimize... *) |
| 783 |
|
if not (Types.Record.has_record constr) then |
| 784 |
and compute_type' loc env = function |
should_have loc constr "but it is a record"; |
| 785 |
| Var s -> |
let (rconstr,res) = |
| 786 |
(try Env.find s env |
List.fold_left |
| 787 |
with Not_found -> raise_loc loc (UnboundId s) |
(fun (rconstr,res) (l,e) -> |
| 788 |
) |
(* could compute (split l e) once... *) |
| 789 |
| Cst c -> Types.constant c |
let pi = Types.Record.project_opt rconstr l in |
| 790 |
| Dot (e,l) -> |
if Types.is_empty pi then |
| 791 |
let t = type_check env e Types.Record.any true in |
(let l = U.to_string (LabelPool.value l) in |
| 792 |
(try (Types.Record.project t l) |
should_have loc constr |
| 793 |
with Not_found -> raise_loc loc (WrongLabel(t,l))) |
(Printf.sprintf "Field %s is not allowed here." l)); |
| 794 |
| RemoveField (e,l) -> |
let t = type_check env e pi true in |
| 795 |
let t = type_check env e Types.Record.any true in |
let rconstr = Types.Record.condition rconstr l t in |
| 796 |
Types.Record.remove_field t l |
let res = (l,Types.cons t) :: res in |
| 797 |
| Op (op, el) -> |
(rconstr,res) |
| 798 |
let args = List.map (fun e -> (e.exp_loc, compute_type env e)) el in |
) (constr, []) (LabelMap.get r) |
|
type_op loc op args |
|
|
| Xtrans (e,b) -> |
|
|
let t = type_check env e Sequence.any true in |
|
|
let r = |
|
|
Sequence.map_tree |
|
|
(fun t -> |
|
|
let resid = Types.diff t b.br_accept in |
|
|
let res = type_check_branches loc env t b Sequence.any true in |
|
|
(res,resid) |
|
|
) t |
|
| 799 |
in |
in |
| 800 |
r |
if not (Types.Record.has_empty_record rconstr) then |
| 801 |
|
should_have loc constr "More fields should be present"; |
| 802 |
|
let t = |
| 803 |
|
Types.record' (false, LabelMap.from_list (fun _ _ -> assert false) res) |
| 804 |
|
in |
| 805 |
|
check loc t constr |
| 806 |
|
|
|
(* We keep these cases here to allow comparison and benchmarking ... |
|
|
Just comment the corresponding cases in type_check' to |
|
|
activate these ones. |
|
|
*) |
|
|
| Pair (e1,e2) -> |
|
|
let t1 = compute_type env e1 |
|
|
and t2 = compute_type env e2 in |
|
|
Types.times (Types.cons t1) (Types.cons t2) |
|
|
| RecordLitt r -> |
|
|
let r = LabelMap.map (fun e -> Types.cons (compute_type env e)) r in |
|
|
Types.record' (false,r) |
|
|
| _ -> assert false |
|
| 807 |
|
|
| 808 |
and type_check_branches loc env targ brs constr precise = |
and type_check_branches loc env targ brs constr precise = |
| 809 |
if Types.is_empty targ then Types.empty |
if Types.is_empty targ then Types.empty |
| 838 |
tres |
tres |
| 839 |
) |
) |
| 840 |
|
|
| 841 |
|
and type_map loc env def e b constr precise = |
| 842 |
|
let acc = if def then Sequence.any else Sequence.star b.br_accept in |
| 843 |
|
let t = type_check env e acc true in |
| 844 |
|
|
| 845 |
|
let constr' = Sequence.approx (Types.cap Sequence.any constr) in |
| 846 |
|
let exact = Types.subtype (Sequence.star constr') constr in |
| 847 |
|
(* Note: |
| 848 |
|
- could be more precise by integrating the decomposition |
| 849 |
|
of constr inside Sequence.map. |
| 850 |
|
*) |
| 851 |
|
let res = |
| 852 |
|
Sequence.map |
| 853 |
|
(fun t -> |
| 854 |
|
let res = |
| 855 |
|
type_check_branches loc env t b constr' (precise || (not exact)) in |
| 856 |
|
if def && not (Types.subtype t b.br_accept) |
| 857 |
|
then Types.cup res Sequence.nil_type |
| 858 |
|
else res) |
| 859 |
|
t in |
| 860 |
|
if exact then res else check loc res constr |
| 861 |
|
|
| 862 |
and type_let_decl env l = |
and type_let_decl env l = |
| 863 |
let acc = Types.descr (Patterns.accept l.let_pat) in |
let acc = Types.descr (Patterns.accept l.let_pat) in |
| 864 |
let t = type_check env l.let_body acc true in |
let t = type_check env l.let_body acc true in |
| 884 |
| _ -> assert false) l; |
| _ -> assert false) l; |
| 885 |
types |
types |
| 886 |
|
|
|
|
|
|
and type_op loc op args = |
|
|
match (op,args) with |
|
|
| "+", [loc1,t1; loc2,t2] -> |
|
|
if (Types.is_empty t1) || (Types.is_empty t2) then Types.empty |
|
|
else if Types.subtype t1 Types.Int.any |
|
|
then ( |
|
|
check loc2 t2 Types.Int.any |
|
|
"The second argument of + must be an integer as the first one"; |
|
|
Types.interval |
|
|
(Intervals.add (Types.Int.get t1) (Types.Int.get t2)) |
|
|
) |
|
|
else ( |
|
|
check loc1 t1 Types.Record.any |
|
|
"The first argument of + must be a record or an integer"; |
|
|
check loc2 t2 Types.Record.any |
|
|
"The second argument of + must be a record as the first one"; |
|
|
Types.Record.merge t1 t2 |
|
|
) |
|
|
| "-", [loc1,t1; loc2,t2] -> |
|
|
type_int_binop Intervals.sub loc1 t1 loc2 t2 |
|
|
| ("*" | "/" | "mod"), [loc1,t1; loc2,t2] -> |
|
|
type_int_binop (fun i1 i2 -> Intervals.any) loc1 t1 loc2 t2 |
|
|
| "@", [loc1,t1; loc2,t2] -> |
|
|
check loc1 t1 Sequence.any |
|
|
"The first argument of @ must be a sequence"; |
|
|
Sequence.concat t1 t2 |
|
|
| "flatten", [loc1,t1] -> |
|
|
check loc1 t1 Sequence.seqseq |
|
|
"The argument of flatten must be a sequence of sequences"; |
|
|
Sequence.flatten t1 |
|
|
| "load_xml", [loc1,t1] -> |
|
|
check loc1 t1 Sequence.string |
|
|
"The argument of load_xml must be a string (filename)"; |
|
|
Types.any |
|
|
| "load_file_utf8", [loc1,t1] -> |
|
|
check loc1 t1 Sequence.string |
|
|
"The argument of load_file must be a string (filename)"; |
|
|
Sequence.string |
|
|
| "load_file", [loc1,t1] -> |
|
|
check loc1 t1 Sequence.string |
|
|
"The argument of load_file must be a string (filename)"; |
|
|
Builtin.string_latin1 |
|
|
| "load_html", [loc1,t1] -> |
|
|
check loc1 t1 Sequence.string |
|
|
"The argument of load_html must be a string (filename)"; |
|
|
Types.any |
|
|
| "raise", [loc1,t1] -> |
|
|
Types.empty |
|
|
| "print_xml", [loc1,t1] -> |
|
|
Builtin.string_latin1 |
|
|
| "print_xml_utf8", [loc1,t1] -> |
|
|
Sequence.string |
|
|
| "print", [loc1,t1] -> |
|
|
check loc1 t1 Sequence.string |
|
|
"The argument of print must be a string"; |
|
|
if not (Types.subtype t1 Builtin.string_latin1) then |
|
|
warning loc "This application of print may fail"; |
|
|
Sequence.nil_type |
|
|
| "dump_to_file_utf8", [loc1,t1; loc2,t2] -> |
|
|
check loc1 t1 Sequence.string |
|
|
"The argument of dump_to_file_utf8 must be a string (filename)"; |
|
|
check loc2 t2 Sequence.string |
|
|
"The argument of dump_to_file_utf8 must be a string (value to dump)"; |
|
|
Sequence.nil_type |
|
|
| "dump_to_file", [loc1,t1; loc2,t2] -> |
|
|
check loc1 t1 Sequence.string |
|
|
"The argument of dump_to_file must be a string (filename)"; |
|
|
check loc2 t2 Sequence.string |
|
|
"The argument of dump_to_file must be a string (value to dump)"; |
|
|
if not (Types.subtype t2 Builtin.string_latin1) then |
|
|
warning loc "This application of dump_to_file may fail"; |
|
|
Sequence.nil_type |
|
|
| "int_of", [loc1,t1] -> |
|
|
check loc1 t1 Sequence.string |
|
|
"The argument of int_of must be a string"; |
|
|
if not (Types.subtype t1 Builtin.intstr) then |
|
|
warning loc "This application of int_of may fail"; |
|
|
Types.interval Intervals.any |
|
|
| "string_of", [loc1,t1] -> |
|
|
Builtin.string_latin1 |
|
|
| "=", [loc1,t1; loc2,t2] -> |
|
|
(* could prevent comparision of functional value here... *) |
|
|
(* could also handle the case when t1 and t2 are the same |
|
|
singleton type *) |
|
|
if Types.is_empty (Types.cap t1 t2) then |
|
|
Builtin.false_type |
|
|
else |
|
|
Builtin.bool |
|
|
| ("<=" | "<" | ">" | ">=" ), [loc1,t1; loc2,t2] -> |
|
|
(* could prevent comparision of functional value here... *) |
|
|
Builtin.bool |
|
|
| _ -> assert false |
|
|
|
|
|
and type_int_binop f loc1 t1 loc2 t2 = |
|
|
check loc1 t1 Types.Int.any |
|
|
"The first argument must be an integer"; |
|
|
check loc2 t2 Types.Int.any |
|
|
"The second argument must be an integer"; |
|
|
Types.interval |
|
|
(f (Types.Int.get t1) (Types.Int.get t2)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 887 |
let report_unused_branches () = |
let report_unused_branches () = |
| 888 |
List.iter |
List.iter |
| 889 |
(fun b -> |
(fun b -> if not b.br_used then warning b.br_loc "This branch is not used") |
|
if not b.br_used then |
|
|
warning b.br_loc "This branch is not used" |
|
|
) |
|
| 890 |
!all_branches; |
!all_branches; |
| 891 |
all_branches := [] |
all_branches := [] |
| 892 |
|
|