From 381a7c98cd056dd126907ac4b613f5d8ed4ca87e Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Mon, 25 Jul 2022 19:48:46 +0400 Subject: [PATCH] Handle all user generated code errors in the type checker (#394) * Move the missing_definition error to the type checker * Move the parameterised_event and parameterised_state errors to the type checker * Remove check_state_and_event_types from ast_to_fcode * Move missing_init_function to the type checker * Remove the code error last_declaration_must_be_main_contract * Expand the tests for missing init function * Remove found_void error * Move the higher order entrypoint error to type checker * Move invalid_aens_resolve_type error to type checker * Add more tests for AENS.resolve * Add test for AENS.resolve with using * Move invalid_oracle_type error to type checker * Move old code errors tests to compilable_contracts * Remove the file aeso_code_errors.erl * Add comment about state type --- src/aeso_ast_infer_types.erl | 164 ++++++++++++++- src/aeso_ast_to_fcode.erl | 93 ++------- src/aeso_code_errors.erl | 94 --------- src/aeso_compiler.erl | 2 +- src/aeso_errors.erl | 7 + src/aeso_fcode_to_fate.erl | 4 +- test/aeso_aci_tests.erl | 2 +- test/aeso_calldata_tests.erl | 2 +- test/aeso_compiler_tests.erl | 189 ++++++++++-------- test/contracts/aens.aes | 15 +- .../{code_errors => }/bad_aens_resolve.aes | 0 test/contracts/bad_aens_resolve_using.aes | 9 + .../{code_errors => }/child_with_decls.aes | 0 .../code_errors/missing_init_function.aes | 3 - .../{code_errors => }/complex_compare.aes | 0 .../{code_errors => }/complex_compare_leq.aes | 0 .../higher_order_compare.aes | 0 .../higher_order_entrypoint.aes | 0 .../higher_order_entrypoint_return.aes | 0 .../higher_order_map_keys.aes | 0 .../higher_order_query_type.aes | 0 .../higher_order_response_type.aes | 0 .../{code_errors => }/higher_order_state.aes | 0 .../{code_errors => }/missing_definition.aes | 0 ...issing_init_fun_alias_to_alias_to_type.aes | 3 + .../missing_init_fun_alias_to_type.aes | 2 + .../contracts/missing_init_fun_state_unit.aes | 9 + test/contracts/name_clash.aes | 9 +- .../{code_errors => }/parameterised_event.aes | 0 .../{code_errors => }/parameterised_state.aes | 0 .../polymorphic_aens_resolve.aes | 0 .../{code_errors => }/polymorphic_compare.aes | 0 .../polymorphic_entrypoint.aes | 0 .../polymorphic_entrypoint_return.aes | 0 .../polymorphic_map_keys.aes | 0 .../polymorphic_query_type.aes | 0 .../polymorphic_response_type.aes | 0 .../unapplied_contract_call.aes | 0 .../unapplied_named_arg_builtin.aes | 0 39 files changed, 329 insertions(+), 278 deletions(-) delete mode 100644 src/aeso_code_errors.erl rename test/contracts/{code_errors => }/bad_aens_resolve.aes (100%) create mode 100644 test/contracts/bad_aens_resolve_using.aes rename test/contracts/{code_errors => }/child_with_decls.aes (100%) delete mode 100644 test/contracts/code_errors/missing_init_function.aes rename test/contracts/{code_errors => }/complex_compare.aes (100%) rename test/contracts/{code_errors => }/complex_compare_leq.aes (100%) rename test/contracts/{code_errors => }/higher_order_compare.aes (100%) rename test/contracts/{code_errors => }/higher_order_entrypoint.aes (100%) rename test/contracts/{code_errors => }/higher_order_entrypoint_return.aes (100%) rename test/contracts/{code_errors => }/higher_order_map_keys.aes (100%) rename test/contracts/{code_errors => }/higher_order_query_type.aes (100%) rename test/contracts/{code_errors => }/higher_order_response_type.aes (100%) rename test/contracts/{code_errors => }/higher_order_state.aes (100%) rename test/contracts/{code_errors => }/missing_definition.aes (100%) create mode 100644 test/contracts/missing_init_fun_alias_to_alias_to_type.aes create mode 100644 test/contracts/missing_init_fun_alias_to_type.aes create mode 100644 test/contracts/missing_init_fun_state_unit.aes rename test/contracts/{code_errors => }/parameterised_event.aes (100%) rename test/contracts/{code_errors => }/parameterised_state.aes (100%) rename test/contracts/{code_errors => }/polymorphic_aens_resolve.aes (100%) rename test/contracts/{code_errors => }/polymorphic_compare.aes (100%) rename test/contracts/{code_errors => }/polymorphic_entrypoint.aes (100%) rename test/contracts/{code_errors => }/polymorphic_entrypoint_return.aes (100%) rename test/contracts/{code_errors => }/polymorphic_map_keys.aes (100%) rename test/contracts/{code_errors => }/polymorphic_query_type.aes (100%) rename test/contracts/{code_errors => }/polymorphic_response_type.aes (100%) rename test/contracts/{code_errors => }/unapplied_contract_call.aes (100%) rename test/contracts/{code_errors => }/unapplied_named_arg_builtin.aes (100%) diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index 9acf1a3..92a9d10 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -87,7 +87,11 @@ -type byte_constraint() :: {is_bytes, utype()} | {add_bytes, aeso_syntax:ann(), concat | split, utype(), utype(), utype()}. --type constraint() :: named_argument_constraint() | field_constraint() | byte_constraint(). +-type aens_resolve_constraint() :: {aens_resolve_type, utype()}. +-type oracle_type_constraint() :: {oracle_type, aeso_syntax:ann(), utype()}. + +-type constraint() :: named_argument_constraint() | field_constraint() | byte_constraint() + | aens_resolve_constraint() | oracle_type_constraint(). -record(field_info, { ann :: aeso_syntax:ann() @@ -1014,6 +1018,9 @@ infer_contract(Env0, What, Defs0, Options) -> contract -> bind_state(Env1) %% bind state and put end, {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), Functions = Get(function, Defs), %% Check for duplicates in Functions (we turn it into a map below) @@ -1028,8 +1035,10 @@ infer_contract(Env0, What, Defs0, Options) -> {Env4, Defs1} = check_sccs(Env3, FunMap, SCCs, []), %% Remove namespaces used in the current namespace Env5 = Env4#env{ used_namespaces = OldUsedNamespaces }, - %% Check that `init` doesn't read or write the state - check_state_dependencies(Env4, Defs1), + %% Check that `init` doesn't read or write the state and that `init` is not missing + check_state(Env4, Defs1), + %% Check that entrypoints have first-order arg types and return types + check_entrypoints(Defs1), destroy_and_report_type_errors(Env4), %% Add inferred types of definitions {Env5, TypeDefs ++ Decls ++ Defs1}. @@ -1096,6 +1105,7 @@ check_typedef_sccs(Env, TypeMap, [{acyclic, Name} | SCCs], Acc) -> case maps:get(Name, TypeMap, undefined) of undefined -> check_typedef_sccs(Env, TypeMap, SCCs, Acc); %% Builtin type {type_def, Ann, D, Xs, Def0} -> + check_parameterizable(D, Xs), Def = check_event(Env, Name, Ann, check_typedef(bind_tvars(Xs, Env), Def0)), Acc1 = [{type_def, Ann, D, Xs, Def} | Acc], Env1 = bind_type(Name, Ann, {Xs, Def}, Env), @@ -1351,6 +1361,13 @@ check_fields(Env, TypeMap, RecTy, [{field_t, Ann, Id, Type} | Fields]) -> Env1 = bind_field(name(Id), #field_info{ ann = Ann, kind = record, field_t = Type, record_t = RecTy }, Env), check_fields(Env1, TypeMap, RecTy, Fields). +check_parameterizable({id, Ann, "event"}, [_ | _]) -> + type_error({parameterized_event, Ann}); +check_parameterizable({id, Ann, "state"}, [_ | _]) -> + type_error({parameterized_state, Ann}); +check_parameterizable(_Name, _Xs) -> + ok. + check_event(Env, "event", Ann, Def) -> case Def of {variant_t, Cons} -> @@ -1613,8 +1630,51 @@ check_stateful_named_arg(#env{ stateful = false, current_function = Fun }, {id, end; check_stateful_named_arg(_, _, _) -> ok. -%% Check that `init` doesn't read or write the state -check_state_dependencies(Env, Defs) -> +check_entrypoints(Defs) -> + [ ensure_first_order_entrypoint(LetFun) + || LetFun <- Defs, + aeso_syntax:get_ann(entrypoint, LetFun, false) ]. + +ensure_first_order_entrypoint({letfun, Ann, Id = {id, _, Name}, Args, Ret, _}) -> + [ ensure_first_order(ArgType, {higher_order_entrypoint, AnnArg, Id, {argument, ArgId, ArgType}}) + || {typed, AnnArg, ArgId, ArgType} <- Args ], + [ ensure_first_order(Ret, {higher_order_entrypoint, Ann, Id, {result, Ret}}) + || Name /= "init" ], %% init can return higher-order values, since they're written to the store + %% rather than being returned. + ok. + +ensure_first_order(Type, Err) -> + is_first_order(Type) orelse type_error(Err). + +is_first_order({fun_t, _, _, _, _}) -> false; +is_first_order(Ts) when is_list(Ts) -> lists:all(fun is_first_order/1, Ts); +is_first_order(Tup) when is_tuple(Tup) -> is_first_order(tuple_to_list(Tup)); +is_first_order(_) -> true. + +ensure_monomorphic(Type, Err) -> + is_monomorphic(Type) orelse type_error(Err). + +is_monomorphic({tvar, _, _}) -> false; +is_monomorphic(Ts) when is_list(Ts) -> lists:all(fun is_monomorphic/1, Ts); +is_monomorphic(Tup) when is_tuple(Tup) -> is_monomorphic(tuple_to_list(Tup)); +is_monomorphic(_) -> true. + +check_state_init(Env) -> + Top = Env#env.namespace, + StateType = lookup_type(Env, {id, [{origin, system}], "state"}), + case unfold_types_in_type(Env, StateType) of + false -> + ok; + {_, {_, {_, {alias_t, {tuple_t, _, []}}}}} -> %% type state = () + ok; + _ -> + #scope{ ann = AnnCon } = get_scope(Env, Top), + type_error({missing_init_function, {con, AnnCon, lists:last(Top)}}) + end. + +%% Check that `init` doesn't read or write the state and that `init` is defined +%% when the state type is not unit +check_state(Env, Defs) -> Top = Env#env.namespace, GetState = Top ++ ["state"], SetState = Top ++ ["put"], @@ -1623,7 +1683,7 @@ check_state_dependencies(Env, Defs) -> Funs = [ {Top ++ [Name], Fun} || Fun = {letfun, _, {id, _, Name}, _Args, _Type, _GuardedBodies} <- Defs ], Deps = maps:from_list([{Name, UsedNames(Def)} || {Name, Def} <- Funs]), case maps:get(Init, Deps, false) of - false -> ok; %% No init, so nothing to check + false -> get_option(no_code, false) orelse check_state_init(Env); _ -> [ type_error({init_depends_on_state, state, Chain}) || Chain <- get_call_chains(Deps, Init, GetState) ], @@ -1765,12 +1825,17 @@ infer_expr(Env, {app, Ann, Fun, Args0} = App) -> NewFun0 = infer_expr(Env, Fun), NewArgs = [infer_expr(Env, A) || A <- Args], ArgTypes = [T || {typed, _, _, T} <- NewArgs], - NewFun1 = {typed, _, _, FunType} = infer_var_args_fun(Env, NewFun0, NamedArgs1, ArgTypes), + NewFun1 = {typed, _, FunName, FunType} = infer_var_args_fun(Env, NewFun0, NamedArgs1, ArgTypes), When = {infer_app, Fun, NamedArgs1, Args, FunType, ArgTypes}, GeneralResultType = fresh_uvar(Ann), ResultType = fresh_uvar(Ann), unify(Env, FunType, {fun_t, [], NamedArgsVar, ArgTypes, GeneralResultType}, When), when_warning(warn_negative_spend, fun() -> warn_potential_negative_spend(Ann, NewFun1, NewArgs) end), + [ add_constraint({aens_resolve_type, GeneralResultType}) + || element(3, FunName) =:= ["AENS", "resolve"] ], + [ add_constraint({oracle_type, Ann, OType}) + || OType <- [get_oracle_type(FunName, ArgTypes, GeneralResultType)], + OType =/= false ], add_constraint( #dependent_type_constraint{ named_args_t = NamedArgsVar, named_args = NamedArgs1, @@ -2291,11 +2356,19 @@ destroy_and_report_unsolved_constraints(Env) -> (#named_argument_constraint{}) -> true; (_) -> false end, OtherCs2), - {BytesCs, []} = + {BytesCs, OtherCs4} = lists:partition(fun({is_bytes, _}) -> true; ({add_bytes, _, _, _, _, _}) -> true; (_) -> false end, OtherCs3), + {AensResolveCs, OtherCs5} = + lists:partition(fun({aens_resolve_type, _}) -> true; + (_) -> false + end, OtherCs4), + {OracleTypeCs, []} = + lists:partition(fun({oracle_type, _, _}) -> true; + (_) -> false + end, OtherCs5), Unsolved = [ S || S <- [ solve_constraint(Env, dereference_deep(C)) || C <- NamedArgCs ], S == unsolved ], @@ -2313,9 +2386,20 @@ destroy_and_report_unsolved_constraints(Env) -> check_record_create_constraints(Env, CreateCs), check_is_contract_constraints(Env, ContractCs), check_bytes_constraints(Env, BytesCs), + check_aens_resolve_constraints(Env, AensResolveCs), + check_oracle_type_constraints(Env, OracleTypeCs), destroy_constraints(). +get_oracle_type({qid, _, ["Oracle", "register"]}, _ , OType) -> OType; +get_oracle_type({qid, _, ["Oracle", "query"]}, [OType| _], _ ) -> OType; +get_oracle_type({qid, _, ["Oracle", "get_question"]}, [OType| _], _ ) -> OType; +get_oracle_type({qid, _, ["Oracle", "get_answer"]}, [OType| _], _ ) -> OType; +get_oracle_type({qid, _, ["Oracle", "check"]}, [OType| _], _ ) -> OType; +get_oracle_type({qid, _, ["Oracle", "check_query"]}, [OType| _], _ ) -> OType; +get_oracle_type({qid, _, ["Oracle", "respond"]}, [OType| _], _ ) -> OType; +get_oracle_type(_Fun, _Args, _Ret) -> false. + %% -- Named argument constraints -- %% If false, a type error has been emitted, so it's safe to drop the constraint. @@ -2442,6 +2526,32 @@ check_bytes_constraint(Env, {add_bytes, Ann, Fun, A0, B0, C0}) -> _ -> type_error({unsolved_bytes_constraint, Ann, Fun, A, B, C}) end. +check_aens_resolve_constraints(_Env, []) -> + ok; +check_aens_resolve_constraints(Env, [{aens_resolve_type, Type} | Rest]) -> + Type1 = unfold_types_in_type(Env, instantiate(Type)), + {app_t, _, {id, _, "option"}, [Type2]} = Type1, + case Type2 of + {id, _, "string"} -> ok; + {id, _, "address"} -> ok; + {con, _, _} -> ok; + {app_t, _, {id, _, "oracle"}, [_, _]} -> ok; + {app_t, _, {id, _, "oracle_query"}, [_, _]} -> ok; + _ -> type_error({invalid_aens_resolve_type, aeso_syntax:get_ann(Type), Type2}) + end, + check_aens_resolve_constraints(Env, Rest). + +check_oracle_type_constraints(_Env, []) -> + ok; +check_oracle_type_constraints(Env, [{oracle_type, Ann, OType} | Rest]) -> + Type = unfold_types_in_type(Env, instantiate(OType)), + {app_t, _, {id, _, "oracle"}, [QType, RType]} = Type, + ensure_monomorphic(QType, {invalid_oracle_type, polymorphic, query, Ann, Type}), + ensure_monomorphic(RType, {invalid_oracle_type, polymorphic, response, Ann, Type}), + ensure_first_order(QType, {invalid_oracle_type, higher_order, query, Ann, Type}), + ensure_first_order(RType, {invalid_oracle_type, higher_order, response, Ann, Type}), + check_oracle_type_constraints(Env, Rest). + %% -- Field constraints -- check_record_create_constraints(_, []) -> ok; @@ -3485,6 +3595,44 @@ mk_error({unimplemented_interface_function, ConId, InterfaceName, FunName}) -> mk_error({referencing_undefined_interface, InterfaceId}) -> Msg = io_lib:format("Trying to implement or extend an undefined interface `~s`", [pp(InterfaceId)]), 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({parameterized_state, Ann}) -> + Msg = "The state type cannot be parameterized", + mk_t_err(pos(Ann), Msg); +mk_error({parameterized_event, Ann}) -> + Msg = "The event type cannot be parameterized", + mk_t_err(pos(Ann), Msg); +mk_error({missing_init_function, Con}) -> + Msg = io_lib:format("Missing `init` function for the contract `~s`.", [name(Con)]), + Cxt = "The `init` function can only be omitted if the state type is `unit`", + mk_t_err(pos(Con), Msg, Cxt); +mk_error({higher_order_entrypoint, Ann, {id, _, Name}, Thing}) -> + What = "higher-order (contains function types)", + ThingS = case Thing of + {argument, X, T} -> io_lib:format("argument\n~s`\n", [pp_typed(" `", X, T)]); + {result, T} -> io_lib:format("return type\n~s`\n", [pp_type(" `", T)]) + end, + Bad = case Thing of + {argument, _, _} -> io_lib:format("has a ~s type", [What]); + {result, _} -> io_lib:format("is ~s", [What]) + end, + Msg = io_lib:format("The ~sof entrypoint `~s` ~s", + [ThingS, Name, Bad]), + mk_t_err(pos(Ann), Msg); +mk_error({invalid_aens_resolve_type, Ann, T}) -> + Msg = io_lib:format("Invalid return type of `AENS.resolve`:\n" + "~s`\n" + "It must be a `string` or a pubkey type (`address`, `oracle`, etc)", + [pp_type(" `", T)]), + mk_t_err(pos(Ann), Msg); +mk_error({invalid_oracle_type, Why, What, Ann, Type}) -> + WhyS = case Why of higher_order -> "higher-order (contain function types)"; + polymorphic -> "polymorphic (contain type variables)" end, + Msg = io_lib:format("Invalid oracle type\n~s`", [pp_type(" `", Type)]), + Cxt = io_lib:format("The ~s type must not be ~s", [What, WhyS]), + mk_t_err(pos(Ann), Msg, Cxt); mk_error(Err) -> Msg = io_lib:format("Unknown error: ~p", [Err]), mk_t_err(pos(0, 0), Msg). diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index bea8572..a4f7ce6 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -326,7 +326,7 @@ get_option(Opt, Env, Default) -> %% -- Compilation ------------------------------------------------------------ -spec to_fcode(env(), aeso_syntax:ast()) -> {env(), fcode()}. -to_fcode(Env, [{Contract, Attrs, Con = {con, _, Name}, _Impls, Decls}|Rest]) +to_fcode(Env, [{Contract, Attrs, {con, _, Name}, _Impls, Decls}|Rest]) when ?IS_CONTRACT_HEAD(Contract) -> case Contract =:= contract_interface of false -> @@ -349,7 +349,7 @@ to_fcode(Env, [{Contract, Attrs, Con = {con, _, Name}, _Impls, Decls}|Rest]) event_type => EventType, payable => Payable, functions => add_init_function( - Env1, Con, StateType, + Env1, add_event_function(Env1, EventType, Funs)) }, case Contract of contract_main -> [] = Rest, {Env1, ConFcode}; @@ -362,8 +362,6 @@ to_fcode(Env, [{Contract, Attrs, Con = {con, _, Name}, _Impls, Decls}|Rest]) Env1 = decls_to_fcode(Env#{ context => {abstract_contract, Name} }, Decls), to_fcode(Env1, Rest) end; -to_fcode(_Env, [NotMain = {NotMainHead, _ ,_ , _}]) when NotMainHead =/= contract_def -> - fcode_error({last_declaration_must_be_main_contract, NotMain}); to_fcode(Env, [{namespace, _, {con, _, Con}, Decls} | Code]) -> Env1 = decls_to_fcode(Env#{ context => {namespace, Con} }, Decls), to_fcode(Env1, Code). @@ -377,22 +375,15 @@ decls_to_fcode(Env, Decls) -> end, Env1, Decls). -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, {type_def, _Ann, Name, Args, Def}) -> typedef_to_fcode(Env, Name, Args, Def); -decl_to_fcode(Env = #{ functions := Funs }, {letfun, Ann, Id = {id, _, Name}, Args, Ret, [{guarded, _, [], Body}]}) -> +decl_to_fcode(Env = #{ functions := Funs }, {letfun, Ann, {id, _, Name}, Args, Ret, [{guarded, _, [], Body}]}) -> Attrs = get_attributes(Ann), FName = lookup_fun(Env, qname(Env, Name)), FArgs = args_to_fcode(Env, Args), FRet = type_to_fcode(Env, Ret), FBody = expr_to_fcode(Env#{ vars => [X || {X, _} <- FArgs] }, Body), - [ ensure_first_order_entrypoint(Ann, Id, Args, Ret, FArgs, FRet) - || aeso_syntax:get_ann(entrypoint, Ann, false) ], Def = #{ attrs => Attrs, args => FArgs, return => FRet, @@ -401,8 +392,7 @@ decl_to_fcode(Env = #{ functions := Funs }, {letfun, Ann, Id = {id, _, Name}, Ar Env#{ functions := NewFuns }. -spec typedef_to_fcode(env(), aeso_syntax:id(), [aeso_syntax:tvar()], aeso_syntax:typedef()) -> env(). -typedef_to_fcode(Env, Id = {id, _, Name}, Xs, Def) -> - check_state_and_event_types(Env, Id, Xs), +typedef_to_fcode(Env, {id, _, Name}, Xs, Def) -> Q = qname(Env, Name), FDef = fun(Args) when length(Args) == length(Xs) -> Sub = maps:from_list(lists:zip([X || {tvar, _, X} <- Xs], Args)), @@ -466,14 +456,6 @@ compute_state_layout(R, [H | T]) -> compute_state_layout(R, _) -> {R + 1, {reg, R}}. -check_state_and_event_types(#{ context := {contract_def, _} }, Id, [_ | _]) -> - case Id of - {id, _, "state"} -> fcode_error({parameterized_state, Id}); - {id, _, "event"} -> fcode_error({parameterized_event, Id}); - _ -> ok - end; -check_state_and_event_types(_, _, _) -> ok. - -spec type_to_fcode(env(), aeso_syntax:type()) -> ftype(). type_to_fcode(Env, Type) -> type_to_fcode(Env, #{}, Type). @@ -491,8 +473,6 @@ type_to_fcode(Env, Sub, {record_t, Fields}) -> type_to_fcode(Env, Sub, {tuple_t, [], lists:map(FieldType, Fields)}); type_to_fcode(_Env, _Sub, {bytes_t, _, N}) -> {bytes, N}; -type_to_fcode(_Env, _Sub, {tvar, Ann, "void"}) -> - fcode_error({found_void, Ann}); type_to_fcode(_Env, Sub, {tvar, _, X}) -> maps:get(X, Sub, {tvar, X}); type_to_fcode(_Env, _Sub, {fun_t, Ann, _, var_args, _}) -> @@ -554,7 +534,7 @@ expr_to_fcode(_Env, _Type, {bytes, _, B}) -> {lit, {bytes, B}}; %% Variables expr_to_fcode(Env, _Type, {id, _, X}) -> resolve_var(Env, [X]); -expr_to_fcode(Env, Type, {qid, Ann, X}) -> +expr_to_fcode(Env, Type, {qid, _, X}) -> case resolve_var(Env, X) of {builtin_u, B, Ar} when B =:= oracle_query; B =:= oracle_get_question; @@ -565,13 +545,11 @@ expr_to_fcode(Env, Type, {qid, Ann, X}) -> B =:= oracle_check_query -> OType = get_oracle_type(B, Type), {oracle, QType, RType} = type_to_fcode(Env, OType), - validate_oracle_type(Ann, OType, QType, RType), TypeArgs = [{lit, {typerep, QType}}, {lit, {typerep, RType}}], {builtin_u, B, Ar, TypeArgs}; {builtin_u, B = aens_resolve, Ar} -> {fun_t, _, _, _, ResType} = Type, AensType = type_to_fcode(Env, ResType), - validate_aens_resolve_type(Ann, ResType, AensType), TypeArgs = [{lit, {typerep, AensType}}], {builtin_u, B, Ar, TypeArgs}; {builtin_u, B = bytes_split, Ar} -> @@ -824,53 +802,6 @@ get_oracle_type(oracle_check, {fun_t, _, _, [OType | _], _}) -> OType; get_oracle_type(oracle_check_query, {fun_t, _, _, [OType | _], _}) -> OType; get_oracle_type(oracle_respond, {fun_t, _, _, [OType | _], _}) -> OType. -validate_oracle_type(Ann, Type, QType, RType) -> - ensure_monomorphic(QType, {invalid_oracle_type, polymorphic, query, Ann, Type}), - ensure_monomorphic(RType, {invalid_oracle_type, polymorphic, response, Ann, Type}), - ensure_first_order(QType, {invalid_oracle_type, higher_order, query, Ann, Type}), - ensure_first_order(RType, {invalid_oracle_type, higher_order, response, Ann, Type}), - ok. - -validate_aens_resolve_type(Ann, {app_t, _, _, [Type]}, {variant, [[], [FType]]}) -> - case FType of - string -> ok; - address -> ok; - contract -> ok; - {oracle, _, _} -> ok; - oracle_query -> ok; - _ -> fcode_error({invalid_aens_resolve_type, Ann, Type}) - end. - -ensure_first_order_entrypoint(Ann, Id = {id, _, Name}, Args, Ret, FArgs, FRet) -> - [ ensure_first_order(FT, {invalid_entrypoint, higher_order, Ann1, Id, {argument, X, T}}) - || {{typed, Ann1, X, T}, {_, FT}} <- lists:zip(Args, FArgs) ], - [ ensure_first_order(FRet, {invalid_entrypoint, higher_order, Ann, Id, {result, Ret}}) - || Name /= "init" ], %% init can return higher-order values, since they're written to the store - %% rather than being returned. - ok. - -ensure_monomorphic(Type, Err) -> - case is_monomorphic(Type) of - true -> ok; - false -> fcode_error(Err) - end. - -ensure_first_order(Type, Err) -> - case is_first_order(Type) of - true -> ok; - false -> fcode_error(Err) - end. - -is_monomorphic({tvar, _}) -> false; -is_monomorphic(Ts) when is_list(Ts) -> lists:all(fun is_monomorphic/1, Ts); -is_monomorphic(Tup) when is_tuple(Tup) -> is_monomorphic(tuple_to_list(Tup)); -is_monomorphic(_) -> true. - -is_first_order({function, _, _}) -> false; -is_first_order(Ts) when is_list(Ts) -> lists:all(fun is_first_order/1, Ts); -is_first_order(Tup) when is_tuple(Tup) -> is_first_order(tuple_to_list(Tup)); -is_first_order(_) -> true. - %% -- Pattern matching -- -spec alts_to_fcode(env(), ftype(), var_name(), [aeso_syntax:alt()], aeso_syntax:expr()) -> fsplit(). @@ -1203,11 +1134,11 @@ builtin_to_fcode(_Layout, Builtin, Args) -> %% -- Init function -- -add_init_function(Env, Main, StateType, Funs0) -> +add_init_function(Env, Funs0) -> case is_no_code(Env) of true -> Funs0; false -> - Funs = add_default_init_function(Env, Main, StateType, Funs0), + Funs = add_default_init_function(Env, Funs0), InitName = {entrypoint, <<"init">>}, InitFun = #{ body := InitBody} = maps:get(InitName, Funs), Funs1 = Funs#{ InitName => InitFun#{ return => {tuple, []}, @@ -1215,16 +1146,14 @@ add_init_function(Env, Main, StateType, Funs0) -> Funs1 end. -add_default_init_function(_Env, Main, StateType, Funs) -> +add_default_init_function(_Env, Funs) -> InitName = {entrypoint, <<"init">>}, case maps:get(InitName, Funs, none) of - %% Only add default init function if state is unit. - none when StateType == {tuple, []} -> + none -> Funs#{ InitName => #{attrs => [], args => [], return => {tuple, []}, body => {tuple, []}} }; - none -> fcode_error({missing_init_function, Main}); _ -> Funs end. @@ -2090,7 +2019,9 @@ setnth(I, X, Xs) -> -dialyzer({nowarn_function, [fcode_error/1, internal_error/1]}). fcode_error(Error) -> - aeso_errors:throw(aeso_code_errors:format(Error)). + Pos = aeso_errors:pos(0, 0), + Msg = lists:flatten(io_lib:format("Unknown error: ~p\n", [Error])), + aeso_errors:throw(aeso_errors:new(code_error, Pos, Msg)). internal_error(Error) -> Msg = lists:flatten(io_lib:format("~p\n", [Error])), diff --git a/src/aeso_code_errors.erl b/src/aeso_code_errors.erl deleted file mode 100644 index 269d8d7..0000000 --- a/src/aeso_code_errors.erl +++ /dev/null @@ -1,94 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author Ulf Norell -%%% @copyright (C) 2019, Aeternity Anstalt -%%% @doc -%%% Formatting of code generation errors. -%%% @end -%%% -%%%------------------------------------------------------------------- --module(aeso_code_errors). - --export([format/1, pos/1]). - -format({last_declaration_must_be_main_contract, Decl = {Kind, _, {con, _, C}, _}}) -> - Msg = io_lib:format("Expected a main contract as the last declaration instead of the ~p '~s'", - [Kind, C]), - mk_err(pos(Decl), Msg); -format({missing_init_function, 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'.", - 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}) -> - Msg = "The state type cannot be parameterized.", - mk_err(pos(Decl), Msg); -format({parameterized_event, Decl}) -> - Msg = "The event type cannot be parameterized.", - mk_err(pos(Decl), Msg); -format({invalid_entrypoint, Why, Ann, {id, _, Name}, Thing}) -> - What = case Why of higher_order -> "higher-order (contains function types)"; - polymorphic -> "polymorphic (contains type variables)" end, - ThingS = case Thing of - {argument, X, T} -> io_lib:format("argument\n~s\n", [pp_typed(X, T)]); - {result, T} -> io_lib:format("return type\n~s\n", [pp_type(2, T)]) - end, - Bad = case Thing of - {argument, _, _} -> io_lib:format("has a ~s type", [What]); - {result, _} -> io_lib:format("is ~s", [What]) - end, - Msg = io_lib:format("The ~sof entrypoint '~s' ~s.", - [ThingS, Name, Bad]), - case Why of - higher_order -> mk_err(pos(Ann), Msg) - end; -format({invalid_aens_resolve_type, Ann, T}) -> - Msg = io_lib:format("Invalid return type of AENS.resolve:\n" - "~s\n" - "It must be a string or a pubkey type (address, oracle, etc).", - [pp_type(2, T)]), - mk_err(pos(Ann), Msg); -format({invalid_oracle_type, Why, What, Ann, Type}) -> - WhyS = case Why of higher_order -> "higher-order (contain function types)"; - polymorphic -> "polymorphic (contain type variables)" end, - Msg = io_lib:format("Invalid oracle type\n~s", [pp_type(2, Type)]), - Cxt = io_lib:format("The ~s type must not be ~s.", [What, WhyS]), - mk_err(pos(Ann), Msg, Cxt); -format({var_args_not_set, Expr}) -> - mk_err( pos(Expr), "Could not deduce type of variable arguments list" - , "When compiling " ++ pp_expr(Expr) - ); -format({found_void, Ann}) -> - mk_err(pos(Ann), "Found a void-typed value.", "`void` is a restricted, uninhabited type. Did you mean `unit`?"); - -format(Err) -> - mk_err(aeso_errors:pos(0, 0), io_lib:format("Unknown error: ~p\n", [Err])). - -pos(Ann) -> - File = aeso_syntax:get_ann(file, Ann, no_file), - Line = aeso_syntax:get_ann(line, Ann, 0), - Col = aeso_syntax:get_ann(col, Ann, 0), - aeso_errors:pos(File, Line, Col). - -pp_typed(E, T) -> - prettypr:format(prettypr:nest(2, - lists:foldr(fun prettypr:beside/2, prettypr:empty(), - [aeso_pretty:expr(E), prettypr:text(" : "), - aeso_pretty:type(T)]))). - -pp_expr(E) -> - pp_expr(0, E). - -pp_expr(N, E) -> - prettypr:format(prettypr:nest(N, aeso_pretty:expr(E))). - -pp_type(N, T) -> - prettypr:format(prettypr:nest(N, aeso_pretty:type(T))). - -mk_err(Pos, Msg) -> - aeso_errors:new(code_error, Pos, lists:flatten(Msg)). - -mk_err(Pos, Msg, Cxt) -> - aeso_errors:new(code_error, Pos, lists:flatten(Msg), lists:flatten(Cxt)). - diff --git a/src/aeso_compiler.erl b/src/aeso_compiler.erl index 2982fd6..d49c47d 100644 --- a/src/aeso_compiler.erl +++ b/src/aeso_compiler.erl @@ -349,7 +349,7 @@ get_decode_type(FunName, [{Contract, Ann, _, _, Defs}]) when ?IS_CONTRACT_HEAD(C "init" -> {ok, [], {tuple_t, [], []}}; _ -> Msg = io_lib:format("Function '~s' is missing in contract", [FunName]), - Pos = aeso_code_errors:pos(Ann), + Pos = aeso_errors:pos(Ann), aeso_errors:throw(aeso_errors:new(data_error, Pos, Msg)) end end; diff --git a/src/aeso_errors.erl b/src/aeso_errors.erl index 8a4ba20..766299d 100644 --- a/src/aeso_errors.erl +++ b/src/aeso_errors.erl @@ -34,6 +34,7 @@ , new/2 , new/3 , new/4 + , pos/1 , pos/2 , pos/3 , pp/1 @@ -53,6 +54,12 @@ new(Type, Pos, Msg) -> new(Type, Pos, Msg, Ctxt) -> #err{ type = Type, pos = Pos, message = Msg, context = Ctxt }. +pos(Ann) -> + File = aeso_syntax:get_ann(file, Ann, no_file), + Line = aeso_syntax:get_ann(line, Ann, 0), + Col = aeso_syntax:get_ann(col, Ann, 0), + pos(File, Line, Col). + pos(Line, Col) -> #pos{ line = Line, col = Col }. diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index ffaf85e..014f319 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -64,7 +64,9 @@ debug(Tag, Options, Fun) -> -dialyzer({nowarn_function, [code_error/1]}). code_error(Err) -> - aeso_errors:throw(aeso_code_errors:format(Err)). + Pos = aeso_errors:pos(0, 0), + Msg = lists:flatten(io_lib:format("Unknown error: ~p\n", [Err])), + aeso_errors:throw(aeso_errors:new(code_error, Pos, Msg)). %% -- Main ------------------------------------------------------------------- diff --git a/test/aeso_aci_tests.erl b/test/aeso_aci_tests.erl index 43ac0c3..70b1600 100644 --- a/test/aeso_aci_tests.erl +++ b/test/aeso_aci_tests.erl @@ -127,7 +127,7 @@ check_stub(Stub, Options) -> Ast -> try %% 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} -> io:format("Type error:\n~s\n", [TE]), error(TE); diff --git a/test/aeso_calldata_tests.erl b/test/aeso_calldata_tests.erl index 2fb7a36..88d7bae 100644 --- a/test/aeso_calldata_tests.erl +++ b/test/aeso_calldata_tests.erl @@ -29,7 +29,7 @@ calldata_aci_test_() -> [ {"Testing " ++ ContractName ++ " contract calling " ++ Fun, fun() -> 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), io:format("ACI:\n~s\n", [ContractACIBin]), FateExprs = ast_exprs(ContractACI, Fun, Args), diff --git a/test/aeso_compiler_tests.erl b/test/aeso_compiler_tests.erl index fe53c95..a10c885 100644 --- a/test/aeso_compiler_tests.erl +++ b/test/aeso_compiler_tests.erl @@ -45,12 +45,6 @@ simple_compile_test_() -> check_errors(ExpectedErrors, Errors) end} || {ContractName, ExpectedErrors} <- failing_contracts() ] ++ - [ {"Testing code generation error messages of " ++ ContractName, - fun() -> - Errors = compile(ContractName), - check_errors([ExpectedError], Errors) - end} || - {ContractName, ExpectedError} <- failing_code_gen_contracts()] ++ [ {"Testing include with explicit files", fun() -> FileSystem = maps:from_list( @@ -208,6 +202,18 @@ compilable_contracts() -> "polymorphism_contract_interface_extensions", "polymorphism_contract_interface_same_decl_multi_interface", "polymorphism_contract_interface_same_name_same_type", + "missing_init_fun_state_unit", + "complex_compare_leq", + "complex_compare", + "higher_order_compare", + "higher_order_map_keys", + "higher_order_state", + "polymorphic_compare", + "polymorphic_entrypoint", + "polymorphic_entrypoint_return", + "polymorphic_map_keys", + "unapplied_contract_call", + "unapplied_named_arg_builtin", "test" % Custom general-purpose test file. Keep it last on the list. ]. @@ -289,34 +295,26 @@ failing_contracts() -> %% Type errors , ?TYPE_ERROR(name_clash, - [<>, + <>, - <>, + <>, - <>, - <>, - <>, - <>, - <>, + <>]) + " - line 10, column 3">>]) , ?TYPE_ERROR(type_errors, [<>, @@ -981,7 +979,8 @@ failing_contracts() -> "when checking the type of the pattern `r10 : rec_inv(Animal)` against the expected type `Main.rec_inv(Cat)`">>, <>]) + "when checking the type of the pattern `r11 : rec_inv(Cat)` against the expected type `Main.rec_inv(Animal)`">> + ]) , ?TYPE_ERROR(polymorphism_variance_switching_oracles, [< "when checking the type of the pattern `q14 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Animal, Cat)`">>, <>]) - ]. - --define(Path(File), "code_errors/" ??File). --define(Msg(File, Line, Col, Err), <>). - --define(FATE_ERR(File, Line, Col, Err), {?Path(File), ?Msg(File, Line, Col, Err)}). - -failing_code_gen_contracts() -> - [ ?FATE_ERR(missing_definition, 2, 14, - "Missing definition of function 'foo'.") - , ?FATE_ERR(higher_order_entrypoint, 2, 20, - "The argument\n" - " f : (int) => int\n" - "of entrypoint 'apply' has a higher-order (contains function types) type.") - , ?FATE_ERR(higher_order_entrypoint_return, 2, 3, - "The return type\n" - " (int) => int\n" - "of entrypoint 'add' is higher-order (contains function types).") - , ?FATE_ERR(missing_init_function, 1, 10, - "Missing init function for the contract 'MissingInitFunction'.\n" - "The 'init' function can only be omitted if the state type is 'unit'.") - , ?FATE_ERR(parameterised_state, 3, 8, - "The state type cannot be parameterized.") - , ?FATE_ERR(parameterised_event, 3, 12, - "The event type cannot be parameterized.") - , ?FATE_ERR(polymorphic_aens_resolve, 4, 5, - "Invalid return type of AENS.resolve:\n" - " 'a\n" - "It must be a string or a pubkey type (address, oracle, etc).") - , ?FATE_ERR(bad_aens_resolve, 6, 5, - "Invalid return type of AENS.resolve:\n" - " list(int)\n" - "It must be a string or a pubkey type (address, oracle, etc).") - , ?FATE_ERR(polymorphic_query_type, 3, 5, - "Invalid oracle type\n" - " oracle('a, 'b)\n" - "The query type must not be polymorphic (contain type variables).") - , ?FATE_ERR(polymorphic_response_type, 3, 5, - "Invalid oracle type\n" - " oracle(string, 'r)\n" - "The response type must not be polymorphic (contain type variables).") - , ?FATE_ERR(higher_order_query_type, 3, 5, - "Invalid oracle type\n" - " oracle((int) => int, string)\n" - "The query type must not be higher-order (contain function types).") - , ?FATE_ERR(higher_order_response_type, 3, 5, - "Invalid oracle type\n" - " oracle(string, (int) => int)\n" - "The response type must not be higher-order (contain function types).") - , ?FATE_ERR(child_with_decls, 2, 14, - "Missing definition of function 'f'.") + "when checking the type of the pattern `q15 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Cat, Animal)`">> + ]) + , ?TYPE_ERROR(missing_definition, + [<> + ]) + , ?TYPE_ERROR(child_with_decls, + [<> + ]) + , ?TYPE_ERROR(parameterised_state, + [<> + ]) + , ?TYPE_ERROR(parameterised_event, + [<> + ]) + , ?TYPE_ERROR(missing_init_fun_alias_to_type, + [<> + ]) + , ?TYPE_ERROR(missing_init_fun_alias_to_alias_to_type, + [<> + ]) + , ?TYPE_ERROR(higher_order_entrypoint, + [< int`\n" + "of entrypoint `apply` has a higher-order (contains function types) type">> + ]) + , ?TYPE_ERROR(higher_order_entrypoint_return, + [< int`\n" + "of entrypoint `add` is higher-order (contains function types)">> + ]) + , ?TYPE_ERROR(polymorphic_aens_resolve, + [<> + ]) + , ?TYPE_ERROR(bad_aens_resolve, + [<> + ]) + , ?TYPE_ERROR(bad_aens_resolve_using, + [<> + ]) + , ?TYPE_ERROR(polymorphic_query_type, + [<>, + <> + ]) + , ?TYPE_ERROR(polymorphic_response_type, + [<> + ]) + , ?TYPE_ERROR(higher_order_query_type, + [< int, string)`\n" + "The query type must not be higher-order (contain function types)">> + ]) + , ?TYPE_ERROR(higher_order_response_type, + [< int)`\n" + "The response type must not be higher-order (contain function types)">> + ]) ]. validation_test_() -> diff --git a/test/contracts/aens.aes b/test/contracts/aens.aes index c342170..698e4c5 100644 --- a/test/contracts/aens.aes +++ b/test/contracts/aens.aes @@ -1,5 +1,7 @@ +contract C = entrypoint init() = () + // AENS tests -contract AENSTest = +main contract AENSTest = // Name resolution @@ -9,10 +11,19 @@ contract AENSTest = stateful entrypoint resolve_string(name : string, key : string) : option(string) = AENS.resolve(name, key) + stateful entrypoint resolve_contract(name : string, key : string) : option(C) = + AENS.resolve(name, key) + + stateful entrypoint resolve_oracle(name : string, key : string) : option(oracle(int, int)) = + AENS.resolve(name, key) + + stateful entrypoint resolve_oracle_query(name : string, key : string) : option(oracle_query(int, int)) = + AENS.resolve(name, key) + // Transactions stateful entrypoint preclaim(addr : address, // Claim on behalf of this account (can be Contract.address) - chash : hash) : unit = // Commitment hash + chash : hash) : unit = // Commitment hash AENS.preclaim(addr, chash) stateful entrypoint signedPreclaim(addr : address, // Claim on behalf of this account (can be Contract.address) diff --git a/test/contracts/code_errors/bad_aens_resolve.aes b/test/contracts/bad_aens_resolve.aes similarity index 100% rename from test/contracts/code_errors/bad_aens_resolve.aes rename to test/contracts/bad_aens_resolve.aes diff --git a/test/contracts/bad_aens_resolve_using.aes b/test/contracts/bad_aens_resolve_using.aes new file mode 100644 index 0000000..8556f46 --- /dev/null +++ b/test/contracts/bad_aens_resolve_using.aes @@ -0,0 +1,9 @@ +contract BadAENSresolve = + using AENS + + type t('a) = option(list('a)) + + function fail() : t(int) = + resolve("foo.aet", "whatever") + + entrypoint main_fun() = () \ No newline at end of file diff --git a/test/contracts/code_errors/child_with_decls.aes b/test/contracts/child_with_decls.aes similarity index 100% rename from test/contracts/code_errors/child_with_decls.aes rename to test/contracts/child_with_decls.aes diff --git a/test/contracts/code_errors/missing_init_function.aes b/test/contracts/code_errors/missing_init_function.aes deleted file mode 100644 index 49372fb..0000000 --- a/test/contracts/code_errors/missing_init_function.aes +++ /dev/null @@ -1,3 +0,0 @@ -contract MissingInitFunction = - type state = int * int - diff --git a/test/contracts/code_errors/complex_compare.aes b/test/contracts/complex_compare.aes similarity index 100% rename from test/contracts/code_errors/complex_compare.aes rename to test/contracts/complex_compare.aes diff --git a/test/contracts/code_errors/complex_compare_leq.aes b/test/contracts/complex_compare_leq.aes similarity index 100% rename from test/contracts/code_errors/complex_compare_leq.aes rename to test/contracts/complex_compare_leq.aes diff --git a/test/contracts/code_errors/higher_order_compare.aes b/test/contracts/higher_order_compare.aes similarity index 100% rename from test/contracts/code_errors/higher_order_compare.aes rename to test/contracts/higher_order_compare.aes diff --git a/test/contracts/code_errors/higher_order_entrypoint.aes b/test/contracts/higher_order_entrypoint.aes similarity index 100% rename from test/contracts/code_errors/higher_order_entrypoint.aes rename to test/contracts/higher_order_entrypoint.aes diff --git a/test/contracts/code_errors/higher_order_entrypoint_return.aes b/test/contracts/higher_order_entrypoint_return.aes similarity index 100% rename from test/contracts/code_errors/higher_order_entrypoint_return.aes rename to test/contracts/higher_order_entrypoint_return.aes diff --git a/test/contracts/code_errors/higher_order_map_keys.aes b/test/contracts/higher_order_map_keys.aes similarity index 100% rename from test/contracts/code_errors/higher_order_map_keys.aes rename to test/contracts/higher_order_map_keys.aes diff --git a/test/contracts/code_errors/higher_order_query_type.aes b/test/contracts/higher_order_query_type.aes similarity index 100% rename from test/contracts/code_errors/higher_order_query_type.aes rename to test/contracts/higher_order_query_type.aes diff --git a/test/contracts/code_errors/higher_order_response_type.aes b/test/contracts/higher_order_response_type.aes similarity index 100% rename from test/contracts/code_errors/higher_order_response_type.aes rename to test/contracts/higher_order_response_type.aes diff --git a/test/contracts/code_errors/higher_order_state.aes b/test/contracts/higher_order_state.aes similarity index 100% rename from test/contracts/code_errors/higher_order_state.aes rename to test/contracts/higher_order_state.aes diff --git a/test/contracts/code_errors/missing_definition.aes b/test/contracts/missing_definition.aes similarity index 100% rename from test/contracts/code_errors/missing_definition.aes rename to test/contracts/missing_definition.aes diff --git a/test/contracts/missing_init_fun_alias_to_alias_to_type.aes b/test/contracts/missing_init_fun_alias_to_alias_to_type.aes new file mode 100644 index 0000000..7514fd0 --- /dev/null +++ b/test/contracts/missing_init_fun_alias_to_alias_to_type.aes @@ -0,0 +1,3 @@ +contract AliasToAliasToType = + type alias = int * int + type state = alias \ No newline at end of file diff --git a/test/contracts/missing_init_fun_alias_to_type.aes b/test/contracts/missing_init_fun_alias_to_type.aes new file mode 100644 index 0000000..3e0b828 --- /dev/null +++ b/test/contracts/missing_init_fun_alias_to_type.aes @@ -0,0 +1,2 @@ +contract AliasToType = + type state = int * int \ No newline at end of file diff --git a/test/contracts/missing_init_fun_state_unit.aes b/test/contracts/missing_init_fun_state_unit.aes new file mode 100644 index 0000000..04603e2 --- /dev/null +++ b/test/contracts/missing_init_fun_state_unit.aes @@ -0,0 +1,9 @@ +contract AliasToAliasToUnit = + type alias = unit + type state = alias + +contract AliasToUnit = + type state = unit + +main contract ImplicitState = + type sometype = int \ No newline at end of file diff --git a/test/contracts/name_clash.aes b/test/contracts/name_clash.aes index 1e8d8e2..2154b80 100644 --- a/test/contracts/name_clash.aes +++ b/test/contracts/name_clash.aes @@ -1,12 +1,5 @@ - 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(y) = 0 @@ -14,4 +7,4 @@ contract NameClash = entrypoint abort() : int = 0 entrypoint require(b, err) = if(b) abort(err) entrypoint put(x) = x - entrypoint state(x, y) = x + y + entrypoint state(x, y) = x + y \ No newline at end of file diff --git a/test/contracts/code_errors/parameterised_event.aes b/test/contracts/parameterised_event.aes similarity index 100% rename from test/contracts/code_errors/parameterised_event.aes rename to test/contracts/parameterised_event.aes diff --git a/test/contracts/code_errors/parameterised_state.aes b/test/contracts/parameterised_state.aes similarity index 100% rename from test/contracts/code_errors/parameterised_state.aes rename to test/contracts/parameterised_state.aes diff --git a/test/contracts/code_errors/polymorphic_aens_resolve.aes b/test/contracts/polymorphic_aens_resolve.aes similarity index 100% rename from test/contracts/code_errors/polymorphic_aens_resolve.aes rename to test/contracts/polymorphic_aens_resolve.aes diff --git a/test/contracts/code_errors/polymorphic_compare.aes b/test/contracts/polymorphic_compare.aes similarity index 100% rename from test/contracts/code_errors/polymorphic_compare.aes rename to test/contracts/polymorphic_compare.aes diff --git a/test/contracts/code_errors/polymorphic_entrypoint.aes b/test/contracts/polymorphic_entrypoint.aes similarity index 100% rename from test/contracts/code_errors/polymorphic_entrypoint.aes rename to test/contracts/polymorphic_entrypoint.aes diff --git a/test/contracts/code_errors/polymorphic_entrypoint_return.aes b/test/contracts/polymorphic_entrypoint_return.aes similarity index 100% rename from test/contracts/code_errors/polymorphic_entrypoint_return.aes rename to test/contracts/polymorphic_entrypoint_return.aes diff --git a/test/contracts/code_errors/polymorphic_map_keys.aes b/test/contracts/polymorphic_map_keys.aes similarity index 100% rename from test/contracts/code_errors/polymorphic_map_keys.aes rename to test/contracts/polymorphic_map_keys.aes diff --git a/test/contracts/code_errors/polymorphic_query_type.aes b/test/contracts/polymorphic_query_type.aes similarity index 100% rename from test/contracts/code_errors/polymorphic_query_type.aes rename to test/contracts/polymorphic_query_type.aes diff --git a/test/contracts/code_errors/polymorphic_response_type.aes b/test/contracts/polymorphic_response_type.aes similarity index 100% rename from test/contracts/code_errors/polymorphic_response_type.aes rename to test/contracts/polymorphic_response_type.aes diff --git a/test/contracts/code_errors/unapplied_contract_call.aes b/test/contracts/unapplied_contract_call.aes similarity index 100% rename from test/contracts/code_errors/unapplied_contract_call.aes rename to test/contracts/unapplied_contract_call.aes diff --git a/test/contracts/code_errors/unapplied_named_arg_builtin.aes b/test/contracts/unapplied_named_arg_builtin.aes similarity index 100% rename from test/contracts/code_errors/unapplied_named_arg_builtin.aes rename to test/contracts/unapplied_named_arg_builtin.aes