More structured errors
This commit is contained in:
parent
963507ddc0
commit
eee4367df9
@ -25,7 +25,43 @@ module Errors = struct
|
|||||||
let message () = "" in
|
let message () = "" in
|
||||||
let data = [
|
let data = [
|
||||||
("variable" , fun () -> Format.asprintf "%s" n) ;
|
("variable" , fun () -> Format.asprintf "%s" n) ;
|
||||||
("in" , fun () -> Format.asprintf "%a" Environment.PP.full_environment e)
|
("environment" , fun () -> Format.asprintf "%a" Environment.PP.full_environment e)
|
||||||
|
] in
|
||||||
|
error ~data title message ()
|
||||||
|
|
||||||
|
let match_empty_variant : type a . a I.matching -> unit -> _ =
|
||||||
|
fun matching () ->
|
||||||
|
let title = (thunk "match with no cases") in
|
||||||
|
let message () = "" in
|
||||||
|
let data = [
|
||||||
|
("variant" , fun () -> Format.asprintf "%a" I.PP.matching_type matching)
|
||||||
|
] in
|
||||||
|
error ~data title message ()
|
||||||
|
|
||||||
|
let match_missing_case : type a . a I.matching -> unit -> _ =
|
||||||
|
fun matching () ->
|
||||||
|
let title = (thunk "missing case in match") in
|
||||||
|
let message () = "" in
|
||||||
|
let data = [
|
||||||
|
("variant" , fun () -> Format.asprintf "%a" I.PP.matching_type matching)
|
||||||
|
] in
|
||||||
|
error ~data title message ()
|
||||||
|
|
||||||
|
let match_redundant_case : type a . a I.matching -> unit -> _ =
|
||||||
|
fun matching () ->
|
||||||
|
let title = (thunk "missing case in match") in
|
||||||
|
let message () = "" in
|
||||||
|
let data = [
|
||||||
|
("variant" , fun () -> Format.asprintf "%a" I.PP.matching_type matching)
|
||||||
|
] in
|
||||||
|
error ~data title message ()
|
||||||
|
|
||||||
|
let unbound_constructor (e:environment) (n:string) () =
|
||||||
|
let title = (thunk "unbound constructor") in
|
||||||
|
let message () = "" in
|
||||||
|
let data = [
|
||||||
|
("constructor" , fun () -> Format.asprintf "%s" n) ;
|
||||||
|
("environment" , fun () -> Format.asprintf "%a" Environment.PP.full_environment e)
|
||||||
] in
|
] in
|
||||||
error ~data title message ()
|
error ~data title message ()
|
||||||
|
|
||||||
@ -73,7 +109,7 @@ module Errors = struct
|
|||||||
] in
|
] in
|
||||||
error ~data title message ()
|
error ~data title message ()
|
||||||
|
|
||||||
let match_error : type a . expected: a I.Types.matching -> actual: O.Types.type_value -> unit -> _ =
|
let match_error : type a . expected: a I.matching -> actual: O.type_value -> unit -> _ =
|
||||||
fun ~expected ~actual () ->
|
fun ~expected ~actual () ->
|
||||||
let title = (thunk "typing match") in
|
let title = (thunk "typing match") in
|
||||||
let message () = "" in
|
let message () = "" in
|
||||||
@ -82,6 +118,42 @@ module Errors = struct
|
|||||||
("actual" , fun () -> Format.asprintf "%a" O.PP.type_value actual)
|
("actual" , fun () -> Format.asprintf "%a" O.PP.type_value actual)
|
||||||
] in
|
] in
|
||||||
error ~data title message ()
|
error ~data title message ()
|
||||||
|
|
||||||
|
let needs_annotation (e : I.expression) (case : string) () =
|
||||||
|
let title = (thunk "this expression must be annotated with its type") in
|
||||||
|
let message () = Format.asprintf "%s needs an annotation" case in
|
||||||
|
let data = [
|
||||||
|
("expression" , fun () -> Format.asprintf "%a" I.PP.expression e)
|
||||||
|
] in
|
||||||
|
error ~data title message ()
|
||||||
|
|
||||||
|
let type_error ~(expected: string) ~(actual: O.type_value) ~(expression : O.value) () =
|
||||||
|
let title = (thunk "this expression must be annotated with its type") in
|
||||||
|
let message () = "" in
|
||||||
|
let data = [
|
||||||
|
("expected" , fun () -> Format.asprintf "%s" expected);
|
||||||
|
("actual" , fun () -> Format.asprintf "%a" O.PP.type_value actual);
|
||||||
|
("expression" , fun () -> Format.asprintf "%a" O.PP.value expression)
|
||||||
|
] in
|
||||||
|
error ~data title message ()
|
||||||
|
|
||||||
|
let bad_tuple_index (index : int) (ae : I.expression) () =
|
||||||
|
let title = (thunk "invalid tuple index") in
|
||||||
|
let message () = "" in
|
||||||
|
let data = [
|
||||||
|
("index" , fun () -> Format.asprintf "%d" index) ;
|
||||||
|
("tuple_value" , fun () -> Format.asprintf "%a" I.PP.expression ae)
|
||||||
|
] in
|
||||||
|
error ~data title message ()
|
||||||
|
|
||||||
|
let bad_record_access (field : string) (ae : I.expression) () =
|
||||||
|
let title = (thunk "invalid record field") in
|
||||||
|
let message () = "" in
|
||||||
|
let data = [
|
||||||
|
("field" , fun () -> Format.asprintf "%s" field) ;
|
||||||
|
("record_value" , fun () -> Format.asprintf "%a" I.PP.expression ae)
|
||||||
|
] in
|
||||||
|
error ~data title message ()
|
||||||
end
|
end
|
||||||
open Errors
|
open Errors
|
||||||
|
|
||||||
@ -147,7 +219,7 @@ and type_match : type i o . (environment -> i -> o result) -> environment -> O.t
|
|||||||
trace_strong (match_error ~expected:i ~actual:t)
|
trace_strong (match_error ~expected:i ~actual:t)
|
||||||
@@ get_t_tuple t in
|
@@ get_t_tuple t in
|
||||||
let%bind lst' =
|
let%bind lst' =
|
||||||
generic_try (simple_error "Matching tuple of different size")
|
generic_try (match_tuple_wrong_arity t_tuple lst)
|
||||||
@@ (fun () -> List.combine lst t_tuple) in
|
@@ (fun () -> List.combine lst t_tuple) in
|
||||||
let aux prev (name, tv) = Environment.add_ez_binder name tv prev in
|
let aux prev (name, tv) = Environment.add_ez_binder name tv prev in
|
||||||
let e' = List.fold_left aux e lst' in
|
let e' = List.fold_left aux e lst' in
|
||||||
@ -157,7 +229,7 @@ and type_match : type i o . (environment -> i -> o result) -> environment -> O.t
|
|||||||
let%bind variant_opt =
|
let%bind variant_opt =
|
||||||
let aux acc ((constructor_name , _) , _) =
|
let aux acc ((constructor_name , _) , _) =
|
||||||
let%bind (_ , variant) =
|
let%bind (_ , variant) =
|
||||||
trace_option (simple_error "bad constructor") @@
|
trace_option (unbound_constructor e constructor_name) @@
|
||||||
Environment.get_constructor constructor_name e in
|
Environment.get_constructor constructor_name e in
|
||||||
let%bind acc = match acc with
|
let%bind acc = match acc with
|
||||||
| None -> ok (Some variant)
|
| None -> ok (Some variant)
|
||||||
@ -166,10 +238,10 @@ and type_match : type i o . (environment -> i -> o result) -> environment -> O.t
|
|||||||
ok (Some variant)
|
ok (Some variant)
|
||||||
) in
|
) in
|
||||||
ok acc in
|
ok acc in
|
||||||
trace (simple_error "in match variant") @@
|
trace (simple_info "in match variant") @@
|
||||||
bind_fold_list aux None lst in
|
bind_fold_list aux None lst in
|
||||||
let%bind variant =
|
let%bind variant =
|
||||||
trace_option (simple_error "empty variant") @@
|
trace_option (match_empty_variant i) @@
|
||||||
variant_opt in
|
variant_opt in
|
||||||
let%bind () =
|
let%bind () =
|
||||||
let%bind variant_cases' =
|
let%bind variant_cases' =
|
||||||
@ -181,17 +253,17 @@ and type_match : type i o . (environment -> i -> o result) -> environment -> O.t
|
|||||||
Assert.assert_true (List.mem c match_cases)
|
Assert.assert_true (List.mem c match_cases)
|
||||||
in
|
in
|
||||||
let%bind () =
|
let%bind () =
|
||||||
trace (simple_error "missing case match") @@
|
trace_strong (match_missing_case i) @@
|
||||||
bind_iter_list test_case variant_cases in
|
bind_iter_list test_case variant_cases in
|
||||||
let%bind () =
|
let%bind () =
|
||||||
trace_strong (simple_error "redundant case match") @@
|
trace_strong (match_redundant_case i) @@
|
||||||
Assert.assert_true List.(length variant_cases = length match_cases) in
|
Assert.assert_true List.(length variant_cases = length match_cases) in
|
||||||
ok ()
|
ok ()
|
||||||
in
|
in
|
||||||
let%bind lst' =
|
let%bind lst' =
|
||||||
let aux ((constructor_name , name) , b) =
|
let aux ((constructor_name , name) , b) =
|
||||||
let%bind (constructor , _) =
|
let%bind (constructor , _) =
|
||||||
trace_option (simple_error "bad constructor??") @@
|
trace_option (unbound_constructor e constructor_name) @@
|
||||||
Environment.get_constructor constructor_name e in
|
Environment.get_constructor constructor_name e in
|
||||||
let e' = Environment.add_ez_binder name constructor e in
|
let e' = Environment.add_ez_binder name constructor e in
|
||||||
let%bind b' = f e' b in
|
let%bind b' = f e' b in
|
||||||
@ -257,7 +329,7 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a
|
|||||||
trace main_error @@
|
trace main_error @@
|
||||||
match Location.unwrap ae with
|
match Location.unwrap ae with
|
||||||
(* Basic *)
|
(* Basic *)
|
||||||
| E_failwith _ -> simple_fail "can't type failwith in isolation"
|
| E_failwith _ -> fail @@ needs_annotation ae "the failwith keyword"
|
||||||
| E_variable name ->
|
| E_variable name ->
|
||||||
let%bind tv' =
|
let%bind tv' =
|
||||||
trace_option (unbound_variable e name)
|
trace_option (unbound_variable e name)
|
||||||
@ -297,14 +369,14 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a
|
|||||||
| Access_tuple index -> (
|
| Access_tuple index -> (
|
||||||
let%bind tpl_tv = get_t_tuple prev.type_annotation in
|
let%bind tpl_tv = get_t_tuple prev.type_annotation in
|
||||||
let%bind tv =
|
let%bind tv =
|
||||||
generic_try (simple_error "bad tuple index")
|
generic_try (bad_tuple_index index ae)
|
||||||
@@ (fun () -> List.nth tpl_tv index) in
|
@@ (fun () -> List.nth tpl_tv index) in
|
||||||
return (E_tuple_accessor (prev , index)) tv
|
return (E_tuple_accessor (prev , index)) tv
|
||||||
)
|
)
|
||||||
| Access_record property -> (
|
| Access_record property -> (
|
||||||
let%bind r_tv = get_t_record prev.type_annotation in
|
let%bind r_tv = get_t_record prev.type_annotation in
|
||||||
let%bind tv =
|
let%bind tv =
|
||||||
generic_try (simple_error "bad record index")
|
generic_try (bad_record_access property ae)
|
||||||
@@ (fun () -> SMap.find property r_tv) in
|
@@ (fun () -> SMap.find property r_tv) in
|
||||||
return (E_record_accessor (prev , property)) tv
|
return (E_record_accessor (prev , property)) tv
|
||||||
)
|
)
|
||||||
@ -316,7 +388,7 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a
|
|||||||
return (E_look_up (prev , ae')) v
|
return (E_look_up (prev , ae')) v
|
||||||
)
|
)
|
||||||
in
|
in
|
||||||
trace (simple_error "accessing") @@
|
trace (simple_info "accessing") @@
|
||||||
bind_fold_list aux e' path
|
bind_fold_list aux e' path
|
||||||
|
|
||||||
(* Sum *)
|
(* Sum *)
|
||||||
@ -360,7 +432,7 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a
|
|||||||
let%bind ty =
|
let%bind ty =
|
||||||
let%bind opt = bind_fold_list aux init
|
let%bind opt = bind_fold_list aux init
|
||||||
@@ List.map get_type_annotation lst' in
|
@@ List.map get_type_annotation lst' in
|
||||||
trace_option (simple_error "empty list expression without annotation") opt in
|
trace_option (needs_annotation ae "empty list") opt in
|
||||||
ok (t_list ty ())
|
ok (t_list ty ())
|
||||||
in
|
in
|
||||||
return (E_list lst') tv
|
return (E_list lst') tv
|
||||||
@ -379,7 +451,7 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a
|
|||||||
@@ List.map get_type_annotation
|
@@ List.map get_type_annotation
|
||||||
@@ List.map fst lst' in
|
@@ List.map fst lst' in
|
||||||
let%bind annot = bind_map_option get_t_map_key tv_opt in
|
let%bind annot = bind_map_option get_t_map_key tv_opt in
|
||||||
trace (simple_error "untyped empty map expression") @@
|
trace (simple_info "empty map expression without a type annotation") @@
|
||||||
O.merge_annotation annot sub
|
O.merge_annotation annot sub
|
||||||
in
|
in
|
||||||
let%bind value_type =
|
let%bind value_type =
|
||||||
@ -388,7 +460,7 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a
|
|||||||
@@ List.map get_type_annotation
|
@@ List.map get_type_annotation
|
||||||
@@ List.map snd lst' in
|
@@ List.map snd lst' in
|
||||||
let%bind annot = bind_map_option get_t_map_value tv_opt in
|
let%bind annot = bind_map_option get_t_map_value tv_opt in
|
||||||
trace (simple_error "untyped empty map expression") @@
|
trace (simple_info "empty map expression without a type annotation") @@
|
||||||
O.merge_annotation annot sub
|
O.merge_annotation annot sub
|
||||||
in
|
in
|
||||||
ok (t_map key_type value_type ())
|
ok (t_map key_type value_type ())
|
||||||
@ -403,7 +475,7 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a
|
|||||||
let%bind input_type =
|
let%bind input_type =
|
||||||
let%bind input_type =
|
let%bind input_type =
|
||||||
(* Hack to take care of let_in introduced by `simplify/ligodity.ml` in ECase's hack *)
|
(* Hack to take care of let_in introduced by `simplify/ligodity.ml` in ECase's hack *)
|
||||||
let default_action () = simple_fail "no input type provided" in
|
let default_action e () = fail @@ (needs_annotation e "the returned value") in
|
||||||
match input_type with
|
match input_type with
|
||||||
| Some ty -> ok ty
|
| Some ty -> ok ty
|
||||||
| None -> (
|
| None -> (
|
||||||
@ -413,11 +485,11 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a
|
|||||||
| I.E_variable name when name = (fst binder) -> (
|
| I.E_variable name when name = (fst binder) -> (
|
||||||
match snd li.binder with
|
match snd li.binder with
|
||||||
| Some ty -> ok ty
|
| Some ty -> ok ty
|
||||||
| None -> default_action ()
|
| None -> default_action li.rhs ()
|
||||||
)
|
)
|
||||||
| _ -> default_action ()
|
| _ -> default_action li.rhs ()
|
||||||
)
|
)
|
||||||
| _ -> default_action ()
|
| _ -> default_action result ()
|
||||||
)
|
)
|
||||||
in
|
in
|
||||||
evaluate_type e input_type in
|
evaluate_type e input_type in
|
||||||
@ -441,7 +513,11 @@ and type_expression : environment -> ?tv_opt:O.type_value -> I.expression -> O.a
|
|||||||
| T_function (param, result) ->
|
| T_function (param, result) ->
|
||||||
let%bind _ = O.assert_type_value_eq (param, arg.type_annotation) in
|
let%bind _ = O.assert_type_value_eq (param, arg.type_annotation) in
|
||||||
ok result
|
ok result
|
||||||
| _ -> simple_fail "applying to not-a-function"
|
| _ ->
|
||||||
|
fail @@ type_error
|
||||||
|
~expected:"should be a function type"
|
||||||
|
~expression:f
|
||||||
|
~actual:f.type_annotation
|
||||||
in
|
in
|
||||||
return (E_application (f , arg)) tv
|
return (E_application (f , arg)) tv
|
||||||
| E_look_up dsi ->
|
| E_look_up dsi ->
|
||||||
|
Loading…
Reference in New Issue
Block a user