Ban empty contracts, ban function blocks with mismatched declarations

This commit is contained in:
radrow 2020-05-15 19:09:08 +02:00
parent 962ddf5303
commit 54e43764ca
5 changed files with 37 additions and 8 deletions

View File

@ -564,6 +564,10 @@ init_env(_Options) -> global_env().
-spec infer(aeso_syntax:ast(), list(option())) -> -spec infer(aeso_syntax:ast(), list(option())) ->
aeso_syntax:ast() | {env(), aeso_syntax:ast()}. aeso_syntax:ast() | {env(), aeso_syntax:ast()}.
infer([], Options) ->
create_type_errors(),
type_error({no_decls, proplists:get_value(src_file, Options, no_file)}),
destroy_and_report_type_errors(init_env(Options));
infer(Contracts, Options) -> infer(Contracts, Options) ->
ets_init(), %% Init the ETS table state ets_init(), %% Init the ETS table state
try try
@ -626,7 +630,9 @@ infer_contract_top(Env, Kind, Defs0, _Options) ->
%% a list of definitions. %% a list of definitions.
-spec infer_contract(env(), main_contract | contract | namespace, [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}. -spec infer_contract(env(), main_contract | contract | namespace, [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}.
infer_contract(Env0, What, Defs0) -> infer_contract(Env0, What, Defs0) ->
create_type_errors(),
Defs = process_blocks(Defs0), Defs = process_blocks(Defs0),
destroy_and_report_type_errors(Env0),
Env = Env0#env{ what = What }, Env = Env0#env{ what = What },
Kind = fun({type_def, _, _, _, _}) -> type; Kind = fun({type_def, _, _, _, _}) -> type;
({letfun, _, _, _, _, _}) -> function; ({letfun, _, _, _, _, _}) -> function;
@ -679,12 +685,12 @@ process_block(Ann, [Decl | Decls]) ->
case Decl of case Decl of
{fun_decl, Ann1, Id = {id, _, Name}, Type} -> {fun_decl, Ann1, Id = {id, _, Name}, Type} ->
{Clauses, Rest} = lists:splitwith(IsThis(Name), Decls), {Clauses, Rest} = lists:splitwith(IsThis(Name), Decls),
[{fun_clauses, Ann1, Id, Type, Clauses} | [type_error({mismatched_decl_in_funblock, Name, D1}) || D1 <- Rest],
process_block(Ann, Rest)]; [{fun_clauses, Ann1, Id, Type, Clauses}];
{letfun, Ann1, Id = {id, _, Name}, _, _, _} -> {letfun, Ann1, Id = {id, _, Name}, _, _, _} ->
{Clauses, Rest} = lists:splitwith(IsThis(Name), [Decl | Decls]), {Clauses, Rest} = lists:splitwith(IsThis(Name), [Decl | Decls]),
[{fun_clauses, Ann1, Id, {id, [{origin, system} | Ann1], "_"}, Clauses} | [type_error({mismatched_decl_in_funblock, Name, D1}) || D1 <- Rest],
process_block(Ann, Rest)] [{fun_clauses, Ann1, Id, {id, [{origin, system} | Ann1], "_"}, Clauses}]
end. end.
-spec check_typedefs(env(), [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}. -spec check_typedefs(env(), [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}.
@ -2266,6 +2272,12 @@ mk_t_err(Pos, Msg) ->
mk_t_err(Pos, Msg, Ctxt) -> mk_t_err(Pos, Msg, Ctxt) ->
aeso_errors:new(type_error, Pos, lists:flatten(Msg), lists:flatten(Ctxt)). aeso_errors:new(type_error, Pos, lists:flatten(Msg), lists:flatten(Ctxt)).
mk_error({no_decls, File}) ->
Pos = aeso_errors:pos(File, 0, 0),
mk_t_err(Pos, "Empty contract\n");
mk_error({mismatched_decl_in_funblock, Name, Decl}) ->
Msg = io_lib:format("Mismatch in the function block. Expected implementation/type declaration of ~s function\n", [Name]),
mk_t_err(pos(Decl), Msg);
mk_error({higher_kinded_typevar, T}) -> mk_error({higher_kinded_typevar, T}) ->
Msg = io_lib:format("Type ~s is a higher kinded type variable\n" Msg = io_lib:format("Type ~s is a higher kinded type variable\n"
"(takes another type as an argument)\n", [pp(instantiate(T))] "(takes another type as an argument)\n", [pp(instantiate(T))]

View File

@ -39,9 +39,9 @@
| {pragma, ann(), pragma()} | {pragma, ann(), pragma()}
| {type_decl, ann(), id(), [tvar()]} % Only for error msgs | {type_decl, ann(), id(), [tvar()]} % Only for error msgs
| {type_def, ann(), id(), [tvar()], typedef()} | {type_def, ann(), id(), [tvar()], typedef()}
| {fun_decl, ann(), id(), type()} | {fun_clauses, ann(), id(), type(), [letfun() | fundecl()]}
| {fun_clauses, ann(), id(), type(), [letbind()]}
| {block, ann(), [decl()]} | {block, ann(), [decl()]}
| fundecl()
| letfun() | letfun()
| letval(). % Only for error msgs | letval(). % Only for error msgs
@ -52,6 +52,8 @@
-type letval() :: {letval, ann(), pat(), expr()}. -type letval() :: {letval, ann(), pat(), expr()}.
-type letfun() :: {letfun, ann(), id(), [pat()], type(), expr()}. -type letfun() :: {letfun, ann(), id(), [pat()], type(), expr()}.
-type fundecl() :: {fun_decl, ann(), id(), type()}.
-type letbind() -type letbind()
:: letfun() :: letfun()
| letval(). | letval().

View File

@ -665,6 +665,16 @@ failing_contracts() ->
"Empty record/map update\n" "Empty record/map update\n"
" r {}">> " r {}">>
]) ])
, ?TYPE_ERROR(bad_function_block,
[<<?Pos(4, 5)
"Mismatch in the function block. Expected implementation/type declaration of g function">>,
<<?Pos(5, 5)
"Mismatch in the function block. Expected implementation/type declaration of g function">>
])
, ?TYPE_ERROR(just_an_empty_file,
[<<?Pos(0, 0)
"Empty contract">>
])
, ?TYPE_ERROR(bad_number_of_args, , ?TYPE_ERROR(bad_number_of_args,
[<<?Pos(3, 39) [<<?Pos(3, 39)
"Cannot unify () => unit\n" "Cannot unify () => unit\n"

View File

@ -0,0 +1,5 @@
contract C =
function
g(1) = 2
f(2) = 3
h(1) = 123

View File