From 7849fe302cf8b08d369b000c6f6f372312b10f35 Mon Sep 17 00:00:00 2001 From: Ulf Norell Date: Tue, 8 Jan 2019 12:27:39 +0100 Subject: [PATCH] Add missing type check of init function --- src/aeso_ast_infer_types.erl | 16 ++++++++++++++++ test/aeso_compiler_tests.erl | 12 ++++++++++-- test/contracts/init_type_error.aes | 8 ++++++++ test/contracts/missing_state_type.aes | 6 ++++++ 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 test/contracts/init_type_error.aes create mode 100644 test/contracts/missing_state_type.aes diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index e78dc83..2a78712 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -352,12 +352,25 @@ check_fundecl(_, {fun_decl, _Attrib, {id, _, Name}, Type}) -> infer_nonrec(Env, LetFun) -> create_constraints(), NewLetFun = infer_letfun(Env, LetFun), + check_special_funs(Env, NewLetFun), solve_constraints(), destroy_and_report_unsolved_constraints(), Result = {TypeSig, _} = instantiate(NewLetFun), print_typesig(TypeSig), Result. +%% Currenty only the init function. +check_special_funs(_Env, {{"init", Type}, _}) -> + {type_sig, Ann, _Named, _Args, Res} = Type, + State = + %% We might have implicit (no) state. + case lookup_type({id, [], "state"}) of + false -> {tuple_t, [{origin, system}], []}; + _ -> {id, [{origin, system}], "state"} + end, + unify(Res, State, {checking_init_type, Ann}); +check_special_funs(_, _) -> ok. + typesig_to_fun_t({type_sig, Ann, Named, Args, Res}) -> {fun_t, Ann, Named, Args, Res}. infer_letrec(Env, {letrec, Attrs, Defs}) -> @@ -1502,6 +1515,9 @@ pp_when({check_expr, Expr, Inferred0, Expected0}) -> "against the expected type\n~s\n", [pp_loc(Expr), pp_typed(" ", Expr, Inferred), pp_type(" ", Expected)]); +pp_when({checking_init_type, Ann}) -> + io_lib:format("when checking that 'init' returns a value of type 'state' at ~s\n", + [pp_loc(Ann)]); pp_when(unknown) -> "". -spec pp_why_record(why_record()) -> iolist(). diff --git a/test/aeso_compiler_tests.erl b/test/aeso_compiler_tests.erl index a9e750d..879aeb2 100644 --- a/test/aeso_compiler_tests.erl +++ b/test/aeso_compiler_tests.erl @@ -21,8 +21,8 @@ simple_compile_test_() -> fun (_) -> ok end, %Cleanup [ {"Testing the " ++ ContractName ++ " contract", fun() -> - #{byte_code := ByteCode, - contract_source := _, + #{byte_code := ByteCode, + contract_source := _, type_info := _} = compile(ContractName), ?assertMatch(Code when is_binary(Code), ByteCode) end} || ContractName <- compilable_contracts() ] ++ @@ -133,4 +133,12 @@ failing_contracts() -> "Repeated name x in pattern\n" " x :: x (at line 26, column 7)\n", "No record type with fields y, z (at line 14, column 22)\n"]} + , {"init_type_error", + ["Cannot unify string\n" + " and map(int, int)\n" + "when checking that 'init' returns a value of type 'state' at line 7, column 3\n"]} + , {"missing_state_type", + ["Cannot unify string\n" + " and ()\n" + "when checking that 'init' returns a value of type 'state' at line 5, column 3\n"]} ]. diff --git a/test/contracts/init_type_error.aes b/test/contracts/init_type_error.aes new file mode 100644 index 0000000..6861a71 --- /dev/null +++ b/test/contracts/init_type_error.aes @@ -0,0 +1,8 @@ + +contract InitTypeError = + + type state = map(int, int) + + // Check that the compiler catches ill-typed init function + function init() = "not the right type!" + diff --git a/test/contracts/missing_state_type.aes b/test/contracts/missing_state_type.aes new file mode 100644 index 0000000..00b7c2b --- /dev/null +++ b/test/contracts/missing_state_type.aes @@ -0,0 +1,6 @@ + +contract MissingStateType = + + // Check that we get a type error also for implicit state + function init() = "should be ()" +