From 54e43764ca6e5f4edb61ac387d8ff16a2ebdea1c Mon Sep 17 00:00:00 2001 From: radrow Date: Fri, 15 May 2020 19:09:08 +0200 Subject: [PATCH] Ban empty contracts, ban function blocks with mismatched declarations --- src/aeso_ast_infer_types.erl | 20 ++++++++++++++++---- src/aeso_syntax.erl | 10 ++++++---- test/aeso_compiler_tests.erl | 10 ++++++++++ test/contracts/bad_function_block.aes | 5 +++++ test/contracts/just_an_empty_file.aes | 0 5 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 test/contracts/bad_function_block.aes create mode 100644 test/contracts/just_an_empty_file.aes diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index 84f8683..d85b3f6 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -564,6 +564,10 @@ init_env(_Options) -> global_env(). -spec infer(aeso_syntax:ast(), list(option())) -> 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) -> ets_init(), %% Init the ETS table state try @@ -626,7 +630,9 @@ infer_contract_top(Env, Kind, Defs0, _Options) -> %% a list of definitions. -spec infer_contract(env(), main_contract | contract | namespace, [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}. infer_contract(Env0, What, Defs0) -> + create_type_errors(), Defs = process_blocks(Defs0), + destroy_and_report_type_errors(Env0), Env = Env0#env{ what = What }, Kind = fun({type_def, _, _, _, _}) -> type; ({letfun, _, _, _, _, _}) -> function; @@ -679,12 +685,12 @@ process_block(Ann, [Decl | Decls]) -> case Decl of {fun_decl, Ann1, Id = {id, _, Name}, Type} -> {Clauses, Rest} = lists:splitwith(IsThis(Name), Decls), - [{fun_clauses, Ann1, Id, Type, Clauses} | - process_block(Ann, Rest)]; + [type_error({mismatched_decl_in_funblock, Name, D1}) || D1 <- Rest], + [{fun_clauses, Ann1, Id, Type, Clauses}]; {letfun, Ann1, Id = {id, _, Name}, _, _, _} -> {Clauses, Rest} = lists:splitwith(IsThis(Name), [Decl | Decls]), - [{fun_clauses, Ann1, Id, {id, [{origin, system} | Ann1], "_"}, Clauses} | - process_block(Ann, Rest)] + [type_error({mismatched_decl_in_funblock, Name, D1}) || D1 <- Rest], + [{fun_clauses, Ann1, Id, {id, [{origin, system} | Ann1], "_"}, Clauses}] end. -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) -> 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}) -> Msg = io_lib:format("Type ~s is a higher kinded type variable\n" "(takes another type as an argument)\n", [pp(instantiate(T))] diff --git a/src/aeso_syntax.erl b/src/aeso_syntax.erl index 30d4d67..1d01ef0 100644 --- a/src/aeso_syntax.erl +++ b/src/aeso_syntax.erl @@ -39,9 +39,9 @@ | {pragma, ann(), pragma()} | {type_decl, ann(), id(), [tvar()]} % Only for error msgs | {type_def, ann(), id(), [tvar()], typedef()} - | {fun_decl, ann(), id(), type()} - | {fun_clauses, ann(), id(), type(), [letbind()]} + | {fun_clauses, ann(), id(), type(), [letfun() | fundecl()]} | {block, ann(), [decl()]} + | fundecl() | letfun() | letval(). % Only for error msgs @@ -50,8 +50,10 @@ -type pragma() :: {compiler, '==' | '<' | '>' | '=<' | '>=', compiler_version()}. --type letval() :: {letval, ann(), pat(), expr()}. --type letfun() :: {letfun, ann(), id(), [pat()], type(), expr()}. +-type letval() :: {letval, ann(), pat(), expr()}. +-type letfun() :: {letfun, ann(), id(), [pat()], type(), expr()}. +-type fundecl() :: {fun_decl, ann(), id(), type()}. + -type letbind() :: letfun() | letval(). diff --git a/test/aeso_compiler_tests.erl b/test/aeso_compiler_tests.erl index c6f5b9f..e8f5931 100644 --- a/test/aeso_compiler_tests.erl +++ b/test/aeso_compiler_tests.erl @@ -665,6 +665,16 @@ failing_contracts() -> "Empty record/map update\n" " r {}">> ]) + , ?TYPE_ERROR(bad_function_block, + [<>, + <> + ]) + , ?TYPE_ERROR(just_an_empty_file, + [<> + ]) , ?TYPE_ERROR(bad_number_of_args, [< unit\n" diff --git a/test/contracts/bad_function_block.aes b/test/contracts/bad_function_block.aes new file mode 100644 index 0000000..53f93b1 --- /dev/null +++ b/test/contracts/bad_function_block.aes @@ -0,0 +1,5 @@ +contract C = + function + g(1) = 2 + f(2) = 3 + h(1) = 123 \ No newline at end of file diff --git a/test/contracts/just_an_empty_file.aes b/test/contracts/just_an_empty_file.aes new file mode 100644 index 0000000..e69de29