Fix parse errors causing crashes instead of nice errors
This commit is contained in:
parent
6ca63e4b40
commit
bf5e2e2443
@ -1290,6 +1290,16 @@ infer_expr(Env, {block, Attrs, Stmts}) ->
|
|||||||
BlockType = fresh_uvar(Attrs),
|
BlockType = fresh_uvar(Attrs),
|
||||||
NewStmts = infer_block(Env, Attrs, Stmts, BlockType),
|
NewStmts = infer_block(Env, Attrs, Stmts, BlockType),
|
||||||
{typed, Attrs, {block, Attrs, NewStmts}, BlockType};
|
{typed, Attrs, {block, Attrs, NewStmts}, BlockType};
|
||||||
|
infer_expr(_Env, {record_or_map_error, Attrs, Fields}) ->
|
||||||
|
type_error({mixed_record_and_map, {record, Attrs, Fields}}),
|
||||||
|
Type = fresh_uvar(Attrs),
|
||||||
|
{typed, Attrs, {record, Attrs, []}, Type};
|
||||||
|
infer_expr(Env, {record_or_map_error, Attrs, Expr, []}) ->
|
||||||
|
type_error({empty_record_or_map_update, {record, Attrs, Expr, []}}),
|
||||||
|
infer_expr(Env, Expr);
|
||||||
|
infer_expr(Env, {record_or_map_error, Attrs, Expr, Fields}) ->
|
||||||
|
type_error({mixed_record_and_map, {record, Attrs, Expr, Fields}}),
|
||||||
|
infer_expr(Env, Expr);
|
||||||
infer_expr(Env, {lam, Attrs, Args, Body}) ->
|
infer_expr(Env, {lam, Attrs, Args, Body}) ->
|
||||||
ArgTypes = [fresh_uvar(As) || {arg, As, _, _} <- Args],
|
ArgTypes = [fresh_uvar(As) || {arg, As, _, _} <- Args],
|
||||||
ArgPatterns = [{typed, As, Pat, check_type(Env, T)} || {arg, As, Pat, T} <- Args],
|
ArgPatterns = [{typed, As, Pat, check_type(Env, T)} || {arg, As, Pat, T} <- Args],
|
||||||
@ -2456,6 +2466,14 @@ mk_error({compiler_version_mismatch, Ann, Version, Op, Bound}) ->
|
|||||||
"because it does not satisfy the constraint"
|
"because it does not satisfy the constraint"
|
||||||
" ~s ~s ~s\n", [PrintV(Version), Op, PrintV(Bound)]),
|
" ~s ~s ~s\n", [PrintV(Version), Op, PrintV(Bound)]),
|
||||||
mk_t_err(pos(Ann), Msg);
|
mk_t_err(pos(Ann), Msg);
|
||||||
|
mk_error({empty_record_or_map_update, Expr}) ->
|
||||||
|
Msg = io_lib:format("Empty record/map update\n~s",
|
||||||
|
[pp_expr(" ", Expr)]),
|
||||||
|
mk_t_err(pos(Expr), Msg);
|
||||||
|
mk_error({mixed_record_and_map, Expr}) ->
|
||||||
|
Msg = io_lib:format("Mixed record fields and map keys in\n~s",
|
||||||
|
[pp_expr(" ", Expr)]),
|
||||||
|
mk_t_err(pos(Expr), Msg);
|
||||||
mk_error(Err) ->
|
mk_error(Err) ->
|
||||||
Msg = io_lib:format("Unknown error: ~p\n", [Err]),
|
Msg = io_lib:format("Unknown error: ~p\n", [Err]),
|
||||||
mk_t_err(pos(0, 0), Msg).
|
mk_t_err(pos(0, 0), Msg).
|
||||||
|
@ -349,7 +349,9 @@ record(Fs) ->
|
|||||||
bad_expr_err("Cannot use '@' in map construction", infix({lvalue, FAnn, LV}, {'@', Ann}, Id));
|
bad_expr_err("Cannot use '@' in map construction", infix({lvalue, FAnn, LV}, {'@', Ann}, Id));
|
||||||
({field, FAnn, LV, _}) ->
|
({field, FAnn, LV, _}) ->
|
||||||
bad_expr_err("Cannot use nested fields or keys in map construction", {lvalue, FAnn, LV}) end,
|
bad_expr_err("Cannot use nested fields or keys in map construction", {lvalue, FAnn, LV}) end,
|
||||||
{map, Ann, lists:map(KV, Fs)}
|
{map, Ann, lists:map(KV, Fs)};
|
||||||
|
record_or_map_error ->
|
||||||
|
{record_or_map_error, get_ann(hd(Fs)), Fs}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
record_or_map(Fields) ->
|
record_or_map(Fields) ->
|
||||||
@ -361,9 +363,7 @@ record_or_map(Fields) ->
|
|||||||
case lists:usort(lists:map(Kind, Fields)) of
|
case lists:usort(lists:map(Kind, Fields)) of
|
||||||
[proj] -> record;
|
[proj] -> record;
|
||||||
[map_get] -> map;
|
[map_get] -> map;
|
||||||
_ ->
|
_ -> record_or_map_error %% Defer error until type checking
|
||||||
[{field, Ann, _, _} | _] = Fields,
|
|
||||||
bad_expr_err("Mixed record fields and map keys in", {record, Ann, Fields})
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
field_assignment() ->
|
field_assignment() ->
|
||||||
|
@ -100,9 +100,8 @@
|
|||||||
| {list, ann(), [expr()]}
|
| {list, ann(), [expr()]}
|
||||||
| {list_comp, ann(), expr(), [comprehension_exp()]}
|
| {list_comp, ann(), expr(), [comprehension_exp()]}
|
||||||
| {typed, ann(), expr(), type()}
|
| {typed, ann(), expr(), type()}
|
||||||
| {record, ann(), [field(expr())]}
|
| {record_or_map(), ann(), [field(expr())]}
|
||||||
| {record, ann(), expr(), [field(expr())]} %% record update
|
| {record_or_map(), ann(), expr(), [field(expr())]} %% record/map update
|
||||||
| {map, ann(), expr(), [field(expr())]} %% map update
|
|
||||||
| {map, ann(), [{expr(), expr()}]}
|
| {map, ann(), [{expr(), expr()}]}
|
||||||
| {map_get, ann(), expr(), expr()}
|
| {map_get, ann(), expr(), expr()}
|
||||||
| {map_get, ann(), expr(), expr(), expr()}
|
| {map_get, ann(), expr(), expr(), expr()}
|
||||||
@ -111,6 +110,8 @@
|
|||||||
| id() | qid() | con() | qcon()
|
| id() | qid() | con() | qcon()
|
||||||
| constant().
|
| constant().
|
||||||
|
|
||||||
|
-type record_or_map() :: record | map | record_or_map_error.
|
||||||
|
|
||||||
-type comprehension_exp() :: [ {comprehension_bind, id(), expr()}
|
-type comprehension_exp() :: [ {comprehension_bind, id(), expr()}
|
||||||
| {comprehension_if, ann(), expr()}
|
| {comprehension_if, ann(), expr()}
|
||||||
| letbind() ].
|
| letbind() ].
|
||||||
|
@ -595,6 +595,17 @@ failing_contracts() ->
|
|||||||
[<<?Pos(5, 28)
|
[<<?Pos(5, 28)
|
||||||
"Invalid call to contract entrypoint 'Foo.foo'.\n"
|
"Invalid call to contract entrypoint 'Foo.foo'.\n"
|
||||||
"It must be called as 'c.foo' for some c : Foo.">>])
|
"It must be called as 'c.foo' for some c : Foo.">>])
|
||||||
|
, ?TYPE_ERROR(bad_records,
|
||||||
|
[<<?Pos(3, 16)
|
||||||
|
"Mixed record fields and map keys in\n"
|
||||||
|
" {x = 0, [0] = 1}">>,
|
||||||
|
<<?Pos(4, 6)
|
||||||
|
"Mixed record fields and map keys in\n"
|
||||||
|
" r {x = 0, [0] = 1}">>,
|
||||||
|
<<?Pos(5, 6)
|
||||||
|
"Empty record/map update\n"
|
||||||
|
" r {}">>
|
||||||
|
])
|
||||||
].
|
].
|
||||||
|
|
||||||
-define(Path(File), "code_errors/" ??File).
|
-define(Path(File), "code_errors/" ??File).
|
||||||
|
5
test/contracts/bad_records.aes
Normal file
5
test/contracts/bad_records.aes
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
contract BadRecord =
|
||||||
|
entrypoint foo() =
|
||||||
|
let r = {x = 0, [0] = 1}
|
||||||
|
r{x = 0, [0] = 1}
|
||||||
|
r{}
|
Loading…
x
Reference in New Issue
Block a user