Move the missing_definition error to the type checker

This commit is contained in:
Gaith Hallak 2022-06-21 14:39:38 +04:00
parent 7b8957b46a
commit 878c229ebd
9 changed files with 27 additions and 42 deletions

View File

@ -1013,6 +1013,9 @@ infer_contract(Env0, What, Defs0, Options) ->
contract -> bind_state(Env1) %% bind state and put contract -> bind_state(Env1) %% bind state and put
end, end,
{ProtoSigs, Decls} = lists:unzip([ check_fundecl(Env1, Decl) || Decl <- Get(prototype, Defs) ]), {ProtoSigs, Decls} = lists:unzip([ check_fundecl(Env1, Decl) || Decl <- Get(prototype, Defs) ]),
[ type_error({missing_definition, Id}) || {fun_decl, _, Id, _} <- Decls,
What =:= contract,
get_option(no_code, false) =:= false ],
Env3 = bind_funs(ProtoSigs, Env2), Env3 = bind_funs(ProtoSigs, Env2),
Functions = Get(function, Defs), Functions = Get(function, Defs),
%% Check for duplicates in Functions (we turn it into a map below) %% Check for duplicates in Functions (we turn it into a map below)
@ -3484,6 +3487,9 @@ mk_error({unimplemented_interface_function, ConId, InterfaceName, FunName}) ->
mk_error({referencing_undefined_interface, InterfaceId}) -> mk_error({referencing_undefined_interface, InterfaceId}) ->
Msg = io_lib:format("Trying to implement or extend an undefined interface `~s`", [pp(InterfaceId)]), Msg = io_lib:format("Trying to implement or extend an undefined interface `~s`", [pp(InterfaceId)]),
mk_t_err(pos(InterfaceId), Msg); mk_t_err(pos(InterfaceId), Msg);
mk_error({missing_definition, Id}) ->
Msg = io_lib:format("Missing definition of function `~s`", [name(Id)]),
mk_t_err(pos(Id), Msg);
mk_error(Err) -> mk_error(Err) ->
Msg = io_lib:format("Unknown error: ~p", [Err]), Msg = io_lib:format("Unknown error: ~p", [Err]),
mk_t_err(pos(0, 0), Msg). mk_t_err(pos(0, 0), Msg).

View File

@ -377,11 +377,6 @@ decls_to_fcode(Env, Decls) ->
end, Env1, Decls). end, Env1, Decls).
-spec decl_to_fcode(env(), aeso_syntax:decl()) -> env(). -spec decl_to_fcode(env(), aeso_syntax:decl()) -> env().
decl_to_fcode(Env = #{context := {contract_def, _}}, {fun_decl, _, Id, _}) ->
case is_no_code(Env) of
false -> fcode_error({missing_definition, Id});
true -> Env
end;
decl_to_fcode(Env, {fun_decl, _, _, _}) -> Env; decl_to_fcode(Env, {fun_decl, _, _, _}) -> Env;
decl_to_fcode(Env, {type_def, _Ann, Name, Args, Def}) -> decl_to_fcode(Env, {type_def, _Ann, Name, Args, Def}) ->
typedef_to_fcode(Env, Name, Args, Def); typedef_to_fcode(Env, Name, Args, Def);

View File

@ -18,9 +18,6 @@ format({missing_init_function, Con}) ->
Msg = io_lib:format("Missing init function for the contract '~s'.", [pp_expr(Con)]), Msg = io_lib:format("Missing init function for the contract '~s'.", [pp_expr(Con)]),
Cxt = "The 'init' function can only be omitted if the state type is 'unit'.", Cxt = "The 'init' function can only be omitted if the state type is 'unit'.",
mk_err(pos(Con), Msg, Cxt); mk_err(pos(Con), Msg, Cxt);
format({missing_definition, Id}) ->
Msg = io_lib:format("Missing definition of function '~s'.", [pp_expr(Id)]),
mk_err(pos(Id), Msg);
format({parameterized_state, Decl}) -> format({parameterized_state, Decl}) ->
Msg = "The state type cannot be parameterized.", Msg = "The state type cannot be parameterized.",
mk_err(pos(Decl), Msg); mk_err(pos(Decl), Msg);

View File

@ -127,7 +127,7 @@ check_stub(Stub, Options) ->
Ast -> Ast ->
try try
%% io:format("AST: ~120p\n", [Ast]), %% io:format("AST: ~120p\n", [Ast]),
aeso_ast_infer_types:infer(Ast, []) aeso_ast_infer_types:infer(Ast, [no_code])
catch throw:{type_errors, TE} -> catch throw:{type_errors, TE} ->
io:format("Type error:\n~s\n", [TE]), io:format("Type error:\n~s\n", [TE]),
error(TE); error(TE);

View File

@ -29,7 +29,7 @@ calldata_aci_test_() ->
[ {"Testing " ++ ContractName ++ " contract calling " ++ Fun, [ {"Testing " ++ ContractName ++ " contract calling " ++ Fun,
fun() -> fun() ->
ContractString = aeso_test_utils:read_contract(ContractName), ContractString = aeso_test_utils:read_contract(ContractName),
{ok, ContractACIBin} = aeso_aci:contract_interface(string, ContractString), {ok, ContractACIBin} = aeso_aci:contract_interface(string, ContractString, [no_code]),
ContractACI = binary_to_list(ContractACIBin), ContractACI = binary_to_list(ContractACIBin),
io:format("ACI:\n~s\n", [ContractACIBin]), io:format("ACI:\n~s\n", [ContractACIBin]),
FateExprs = ast_exprs(ContractACI, Fun, Args), FateExprs = ast_exprs(ContractACI, Fun, Args),

View File

@ -289,34 +289,26 @@ failing_contracts() ->
%% Type errors %% Type errors
, ?TYPE_ERROR(name_clash, , ?TYPE_ERROR(name_clash,
[<<?Pos(14, 3) [<<?Pos(4, 3)
"Duplicate definitions of `double_def` at\n"
" - line 3, column 3\n"
" - line 4, column 3">>,
<<?Pos(7, 3)
"Duplicate definitions of `abort` at\n" "Duplicate definitions of `abort` at\n"
" - (builtin location)\n" " - (builtin location)\n"
" - line 14, column 3">>, " - line 7, column 3">>,
<<?Pos(15, 3) <<?Pos(8, 3)
"Duplicate definitions of `require` at\n" "Duplicate definitions of `require` at\n"
" - (builtin location)\n" " - (builtin location)\n"
" - line 15, column 3">>,
<<?Pos(11, 3)
"Duplicate definitions of `double_def` at\n"
" - line 10, column 3\n"
" - line 11, column 3">>,
<<?Pos(5, 3)
"Duplicate definitions of `double_proto` at\n"
" - line 4, column 3\n"
" - line 5, column 3">>,
<<?Pos(8, 3)
"Duplicate definitions of `proto_and_def` at\n"
" - line 7, column 3\n"
" - line 8, column 3">>, " - line 8, column 3">>,
<<?Pos(16, 3) <<?Pos(9, 3)
"Duplicate definitions of `put` at\n" "Duplicate definitions of `put` at\n"
" - (builtin location)\n" " - (builtin location)\n"
" - line 16, column 3">>, " - line 9, column 3">>,
<<?Pos(17, 3) <<?Pos(10, 3)
"Duplicate definitions of `state` at\n" "Duplicate definitions of `state` at\n"
" - (builtin location)\n" " - (builtin location)\n"
" - line 17, column 3">>]) " - line 10, column 3">>])
, ?TYPE_ERROR(type_errors, , ?TYPE_ERROR(type_errors,
[<<?Pos(17, 23) [<<?Pos(17, 23)
"Unbound variable `zz`">>, "Unbound variable `zz`">>,
@ -1025,6 +1017,12 @@ failing_contracts() ->
<<?Pos(44,13) <<?Pos(44,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n" "Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `q15 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Cat, Animal)`">>]) "when checking the type of the pattern `q15 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Cat, Animal)`">>])
, ?TYPE_ERROR(missing_definition,
[<<?Pos(2,14)
"Missing definition of function `foo`">>])
, ?TYPE_ERROR(child_with_decls,
[<<?Pos(2,14)
"Missing definition of function `f`">>])
]. ].
-define(Path(File), "code_errors/" ??File). -define(Path(File), "code_errors/" ??File).
@ -1033,9 +1031,7 @@ failing_contracts() ->
-define(FATE_ERR(File, Line, Col, Err), {?Path(File), ?Msg(File, Line, Col, Err)}). -define(FATE_ERR(File, Line, Col, Err), {?Path(File), ?Msg(File, Line, Col, Err)}).
failing_code_gen_contracts() -> failing_code_gen_contracts() ->
[ ?FATE_ERR(missing_definition, 2, 14, [ ?FATE_ERR(higher_order_entrypoint, 2, 20,
"Missing definition of function 'foo'.")
, ?FATE_ERR(higher_order_entrypoint, 2, 20,
"The argument\n" "The argument\n"
" f : (int) => int\n" " f : (int) => int\n"
"of entrypoint 'apply' has a higher-order (contains function types) type.") "of entrypoint 'apply' has a higher-order (contains function types) type.")
@ -1074,8 +1070,6 @@ failing_code_gen_contracts() ->
"Invalid oracle type\n" "Invalid oracle type\n"
" oracle(string, (int) => int)\n" " oracle(string, (int) => int)\n"
"The response type must not be higher-order (contain function types).") "The response type must not be higher-order (contain function types).")
, ?FATE_ERR(child_with_decls, 2, 14,
"Missing definition of function 'f'.")
]. ].
validation_test_() -> validation_test_() ->

View File

@ -1,12 +1,5 @@
contract NameClash = contract NameClash =
entrypoint double_proto : () => int
entrypoint double_proto : () => int
entrypoint proto_and_def : int => int
entrypoint proto_and_def(n) = n + 1
entrypoint double_def(x) = x entrypoint double_def(x) = x
entrypoint double_def(y) = 0 entrypoint double_def(y) = 0
@ -14,4 +7,4 @@ contract NameClash =
entrypoint abort() : int = 0 entrypoint abort() : int = 0
entrypoint require(b, err) = if(b) abort(err) entrypoint require(b, err) = if(b) abort(err)
entrypoint put(x) = x entrypoint put(x) = x
entrypoint state(x, y) = x + y entrypoint state(x, y) = x + y