Framework and tests for code generation (icode/fcode) errors
This commit is contained in:
parent
f2469a676d
commit
510935d945
@ -74,19 +74,9 @@ do_contract_interface(Type, ContractString, Options) ->
|
|||||||
string -> do_render_aci_json(JArray)
|
string -> do_render_aci_json(JArray)
|
||||||
end
|
end
|
||||||
catch
|
catch
|
||||||
throw:{type_errors, Errors} -> {error, Errors};
|
throw:{error, Errors} -> {error, Errors}
|
||||||
%% The compiler errors.
|
|
||||||
error:{parse_errors, Errors} ->
|
|
||||||
{error, join_errors("Parse errors", Errors, fun(E) -> E end)};
|
|
||||||
error:{code_errors, Errors} ->
|
|
||||||
{error, join_errors("Code errors", Errors,
|
|
||||||
fun (E) -> io_lib:format("~p", [E]) end)}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
join_errors(Prefix, Errors, Pfun) ->
|
|
||||||
Ess = [ Pfun(E) || E <- Errors ],
|
|
||||||
list_to_binary(string:join([Prefix|Ess], "\n")).
|
|
||||||
|
|
||||||
encode_contract(Contract = {contract, _, {con, _, Name}, _}) ->
|
encode_contract(Contract = {contract, _, {con, _, Name}, _}) ->
|
||||||
C0 = #{name => encode_name(Name)},
|
C0 = #{name => encode_name(Name)},
|
||||||
|
|
||||||
|
@ -2069,7 +2069,7 @@ destroy_and_report_type_errors(Env) ->
|
|||||||
%% io:format("Type errors now: ~p\n", [Errors0]),
|
%% io:format("Type errors now: ~p\n", [Errors0]),
|
||||||
ets_delete(type_errors),
|
ets_delete(type_errors),
|
||||||
Errors = [ mk_error(unqualify(Env, Err)) || Err <- Errors0 ],
|
Errors = [ mk_error(unqualify(Env, Err)) || Err <- Errors0 ],
|
||||||
Errors == [] orelse throw({type_errors, Errors}).
|
aeso_errors:throw(Errors). %% No-op if Errors == []
|
||||||
|
|
||||||
%% Strip current namespace from error message for nicer printing.
|
%% Strip current namespace from error message for nicer printing.
|
||||||
unqualify(#env{ namespace = NS }, {qid, Ann, Xs}) ->
|
unqualify(#env{ namespace = NS }, {qid, Ann, Xs}) ->
|
||||||
|
@ -232,7 +232,7 @@ is_no_code(Env) ->
|
|||||||
%% -- Compilation ------------------------------------------------------------
|
%% -- Compilation ------------------------------------------------------------
|
||||||
|
|
||||||
-spec to_fcode(env(), aeso_syntax:ast()) -> fcode().
|
-spec to_fcode(env(), aeso_syntax:ast()) -> fcode().
|
||||||
to_fcode(Env, [{contract, Attrs, {con, _, Main}, Decls}]) ->
|
to_fcode(Env, [{contract, Attrs, MainCon = {con, _, Main}, Decls}]) ->
|
||||||
#{ builtins := Builtins } = Env,
|
#{ builtins := Builtins } = Env,
|
||||||
MainEnv = Env#{ context => {main_contract, Main},
|
MainEnv = Env#{ context => {main_contract, Main},
|
||||||
builtins => Builtins#{[Main, "state"] => {get_state, none},
|
builtins => Builtins#{[Main, "state"] => {get_state, none},
|
||||||
@ -247,8 +247,10 @@ to_fcode(Env, [{contract, Attrs, {con, _, Main}, Decls}]) ->
|
|||||||
state_type => StateType,
|
state_type => StateType,
|
||||||
event_type => EventType,
|
event_type => EventType,
|
||||||
payable => Payable,
|
payable => Payable,
|
||||||
functions => add_init_function(Env1, StateType,
|
functions => add_init_function(Env1, MainCon, StateType,
|
||||||
add_event_function(Env1, EventType, Funs)) };
|
add_event_function(Env1, EventType, Funs)) };
|
||||||
|
to_fcode(_Env, [NotContract]) ->
|
||||||
|
fcode_error({last_declaration_must_be_contract, NotContract});
|
||||||
to_fcode(Env, [{contract, _, {con, _, Con}, Decls} | Code]) ->
|
to_fcode(Env, [{contract, _, {con, _, Con}, Decls} | Code]) ->
|
||||||
Env1 = decls_to_fcode(Env#{ context => {abstract_contract, Con} }, Decls),
|
Env1 = decls_to_fcode(Env#{ context => {abstract_contract, Con} }, Decls),
|
||||||
to_fcode(Env1, Code);
|
to_fcode(Env1, Code);
|
||||||
@ -294,9 +296,10 @@ decl_to_fcode(Env = #{ functions := Funs }, {letfun, Ann, {id, _, Name}, Args, R
|
|||||||
Env#{ functions := NewFuns }.
|
Env#{ functions := NewFuns }.
|
||||||
|
|
||||||
-spec typedef_to_fcode(env(), aeso_syntax:id(), [aeso_syntax:tvar()], aeso_syntax:typedef()) -> env().
|
-spec typedef_to_fcode(env(), aeso_syntax:id(), [aeso_syntax:tvar()], aeso_syntax:typedef()) -> env().
|
||||||
typedef_to_fcode(Env, {id, _, Name}, Xs, Def) ->
|
typedef_to_fcode(Env, Id = {id, _, Name}, Xs, Def) ->
|
||||||
|
check_state_and_event_types(Env, Id, Xs),
|
||||||
Q = qname(Env, Name),
|
Q = qname(Env, Name),
|
||||||
FDef = fun(Args) ->
|
FDef = fun(Args) when length(Args) == length(Xs) ->
|
||||||
Sub = maps:from_list(lists:zip([X || {tvar, _, X} <- Xs], Args)),
|
Sub = maps:from_list(lists:zip([X || {tvar, _, X} <- Xs], Args)),
|
||||||
case Def of
|
case Def of
|
||||||
{record_t, Fields} -> {todo, Xs, Args, record_t, Fields};
|
{record_t, Fields} -> {todo, Xs, Args, record_t, Fields};
|
||||||
@ -307,7 +310,9 @@ typedef_to_fcode(Env, {id, _, Name}, Xs, Def) ->
|
|||||||
end || Con <- Cons ],
|
end || Con <- Cons ],
|
||||||
{variant, FCons};
|
{variant, FCons};
|
||||||
{alias_t, Type} -> {todo, Xs, Args, alias_t, Type}
|
{alias_t, Type} -> {todo, Xs, Args, alias_t, Type}
|
||||||
end end,
|
end;
|
||||||
|
(Args) -> internal_error({type_arity_mismatch, Name, length(Args), length(Xs)})
|
||||||
|
end,
|
||||||
Constructors =
|
Constructors =
|
||||||
case Def of
|
case Def of
|
||||||
{variant_t, Cons} ->
|
{variant_t, Cons} ->
|
||||||
@ -328,6 +333,14 @@ typedef_to_fcode(Env, {id, _, Name}, Xs, Def) ->
|
|||||||
end,
|
end,
|
||||||
bind_type(Env2, Q, FDef).
|
bind_type(Env2, Q, FDef).
|
||||||
|
|
||||||
|
check_state_and_event_types(#{ context := {main_contract, _} }, 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().
|
-spec type_to_fcode(env(), aeso_syntax:type()) -> ftype().
|
||||||
type_to_fcode(Env, Type) ->
|
type_to_fcode(Env, Type) ->
|
||||||
type_to_fcode(Env, #{}, Type).
|
type_to_fcode(Env, #{}, Type).
|
||||||
@ -533,7 +546,7 @@ expr_to_fcode(Env, Type, {app, _, Fun = {typed, _, _, {fun_t, _, NamedArgsT, _,
|
|||||||
{builtin_u, B, _} when B =:= aens_resolve ->
|
{builtin_u, B, _} when B =:= aens_resolve ->
|
||||||
%% Get the type we are assuming the name resolves to
|
%% Get the type we are assuming the name resolves to
|
||||||
AensType = type_to_fcode(Env, Type),
|
AensType = type_to_fcode(Env, Type),
|
||||||
validate_aens_resolve_type(aeso_syntax:get_ann(Fun), AensType),
|
validate_aens_resolve_type(aeso_syntax:get_ann(Fun), Type, AensType),
|
||||||
TypeArgs = [{lit, {typerep, AensType}}],
|
TypeArgs = [{lit, {typerep, AensType}}],
|
||||||
builtin_to_fcode(B, FArgs ++ TypeArgs);
|
builtin_to_fcode(B, FArgs ++ TypeArgs);
|
||||||
{builtin_u, B, _Ar} -> builtin_to_fcode(B, FArgs);
|
{builtin_u, B, _Ar} -> builtin_to_fcode(B, FArgs);
|
||||||
@ -616,10 +629,15 @@ validate_oracle_type(Ann, QType, RType) ->
|
|||||||
ensure_first_order(RType, {higher_order_response_type, Ann, RType}),
|
ensure_first_order(RType, {higher_order_response_type, Ann, RType}),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
validate_aens_resolve_type(Ann, {variant, [[], [Type]]}) ->
|
validate_aens_resolve_type(Ann, {app_t, _, _, [Type]}, {variant, [[], [FType]]}) ->
|
||||||
ensure_monomorphic(Type, {polymorphic_aens_resolve, Ann, Type}),
|
case FType of
|
||||||
ensure_first_order(Type, {higher_order_aens_resolve, Ann, Type}),
|
string -> ok;
|
||||||
ok.
|
address -> ok;
|
||||||
|
contract -> ok;
|
||||||
|
{oracle, _, _} -> ok;
|
||||||
|
oracle_query -> ok;
|
||||||
|
_ -> fcode_error({invalid_aens_resolve_type, Ann, Type})
|
||||||
|
end.
|
||||||
|
|
||||||
ensure_first_order_entrypoint(Ann, Args, Ret) ->
|
ensure_first_order_entrypoint(Ann, Args, Ret) ->
|
||||||
[ ensure_first_order(T, {higher_order_entrypoint_argument, Ann, X, T})
|
[ ensure_first_order(T, {higher_order_entrypoint_argument, Ann, X, T})
|
||||||
@ -904,18 +922,18 @@ builtin_to_fcode(Builtin, Args) ->
|
|||||||
|
|
||||||
%% -- Init function --
|
%% -- Init function --
|
||||||
|
|
||||||
add_init_function(Env, StateType, Funs0) ->
|
add_init_function(Env, Main, StateType, Funs0) ->
|
||||||
case is_no_code(Env) of
|
case is_no_code(Env) of
|
||||||
true -> Funs0;
|
true -> Funs0;
|
||||||
false ->
|
false ->
|
||||||
Funs = add_default_init_function(Env, StateType, Funs0),
|
Funs = add_default_init_function(Env, Main, StateType, Funs0),
|
||||||
InitName = {entrypoint, <<"init">>},
|
InitName = {entrypoint, <<"init">>},
|
||||||
InitFun = #{ body := InitBody} = maps:get(InitName, Funs),
|
InitFun = #{ body := InitBody} = maps:get(InitName, Funs),
|
||||||
Funs#{ InitName => InitFun#{ return => {tuple, []},
|
Funs#{ InitName => InitFun#{ return => {tuple, []},
|
||||||
body => {builtin, set_state, [InitBody]} } }
|
body => {builtin, set_state, [InitBody]} } }
|
||||||
end.
|
end.
|
||||||
|
|
||||||
add_default_init_function(_Env, StateType, Funs) ->
|
add_default_init_function(_Env, Main, StateType, Funs) ->
|
||||||
InitName = {entrypoint, <<"init">>},
|
InitName = {entrypoint, <<"init">>},
|
||||||
case maps:get(InitName, Funs, none) of
|
case maps:get(InitName, Funs, none) of
|
||||||
%% Only add default init function if state is unit.
|
%% Only add default init function if state is unit.
|
||||||
@ -924,7 +942,7 @@ add_default_init_function(_Env, StateType, Funs) ->
|
|||||||
args => [],
|
args => [],
|
||||||
return => {tuple, []},
|
return => {tuple, []},
|
||||||
body => {tuple, []}} };
|
body => {tuple, []}} };
|
||||||
none -> fcode_error(missing_init_function);
|
none -> fcode_error({missing_init_function, Main});
|
||||||
_ -> Funs
|
_ -> Funs
|
||||||
end.
|
end.
|
||||||
|
|
||||||
@ -1115,7 +1133,7 @@ lookup_type(Env, {qid, _, Name}, Args) ->
|
|||||||
lookup_type(Env, Name, Args);
|
lookup_type(Env, Name, Args);
|
||||||
lookup_type(Env, Name, Args) ->
|
lookup_type(Env, Name, Args) ->
|
||||||
case lookup_type(Env, Name, Args, not_found) of
|
case lookup_type(Env, Name, Args, not_found) of
|
||||||
not_found -> error({unknown_type, Name});
|
not_found -> internal_error({unknown_type, Name});
|
||||||
Type -> Type
|
Type -> Type
|
||||||
end.
|
end.
|
||||||
|
|
||||||
@ -1440,8 +1458,12 @@ get_attributes(Ann) ->
|
|||||||
indexed(Xs) ->
|
indexed(Xs) ->
|
||||||
lists:zip(lists:seq(1, length(Xs)), Xs).
|
lists:zip(lists:seq(1, length(Xs)), Xs).
|
||||||
|
|
||||||
fcode_error(Err) ->
|
fcode_error(Error) ->
|
||||||
error(Err).
|
aeso_errors:throw(aeso_code_errors:format(Error)).
|
||||||
|
|
||||||
|
internal_error(Error) ->
|
||||||
|
Msg = lists:flatten(io_lib:format("~p\n", [Error])),
|
||||||
|
aeso_errors:throw(aeso_errors:new(internal_error, aeso_errors:pos(0, 0), Msg)).
|
||||||
|
|
||||||
%% -- Pretty printing --------------------------------------------------------
|
%% -- Pretty printing --------------------------------------------------------
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ convert_typed(TypedTree, Options) ->
|
|||||||
case lists:last(TypedTree) of
|
case lists:last(TypedTree) of
|
||||||
{contract, Attrs, {con, _, Con}, _} ->
|
{contract, Attrs, {con, _, Con}, _} ->
|
||||||
{proplists:get_value(payable, Attrs, false), Con};
|
{proplists:get_value(payable, Attrs, false), Con};
|
||||||
_ ->
|
Decl ->
|
||||||
gen_error(last_declaration_must_be_contract)
|
gen_error({last_declaration_must_be_contract, Decl})
|
||||||
end,
|
end,
|
||||||
NewIcode = aeso_icode:set_payable(Payable,
|
NewIcode = aeso_icode:set_payable(Payable,
|
||||||
aeso_icode:set_name(Name, aeso_icode:new(Options))),
|
aeso_icode:set_name(Name, aeso_icode:new(Options))),
|
||||||
@ -42,17 +42,17 @@ code([], Icode, Options) ->
|
|||||||
%% Generate error on correct format.
|
%% Generate error on correct format.
|
||||||
|
|
||||||
gen_error(Error) ->
|
gen_error(Error) ->
|
||||||
error({code_errors, [Error]}).
|
aeso_errors:throw(aeso_code_errors:format(Error)).
|
||||||
|
|
||||||
%% Create default init function (only if state is unit).
|
%% Create default init function (only if state is unit).
|
||||||
add_default_init_function(Icode = #{functions := Funs, state_type := State}, Options) ->
|
add_default_init_function(Icode = #{namespace := NS, functions := Funs, state_type := State}, Options) ->
|
||||||
NoCode = proplists:get_value(no_code, Options, false),
|
NoCode = proplists:get_value(no_code, Options, false),
|
||||||
{_, _, QInit} = aeso_icode:qualify({id, [], "init"}, Icode),
|
{_, _, QInit} = aeso_icode:qualify({id, [], "init"}, Icode),
|
||||||
case lists:keymember(QInit, 1, Funs) of
|
case lists:keymember(QInit, 1, Funs) of
|
||||||
true -> Icode;
|
true -> Icode;
|
||||||
false when NoCode -> Icode;
|
false when NoCode -> Icode;
|
||||||
false when State /= {tuple, []} ->
|
false when State /= {tuple, []} ->
|
||||||
gen_error(missing_init_function);
|
gen_error({missing_init_function, NS});
|
||||||
false ->
|
false ->
|
||||||
Type = {tuple, [typerep, {tuple, []}]},
|
Type = {tuple, [typerep, {tuple, []}]},
|
||||||
Value = #tuple{ cpts = [type_value({tuple, []}), {tuple, []}] },
|
Value = #tuple{ cpts = [type_value({tuple, []}), {tuple, []}] },
|
||||||
@ -83,9 +83,9 @@ contract_to_icode([{type_def, _Attrib, Id = {id, _, Name}, Args, Def} | Rest],
|
|||||||
constructors := maps:merge(Constructors, NewConstructors) },
|
constructors := maps:merge(Constructors, NewConstructors) },
|
||||||
Icode2 = case Name of
|
Icode2 = case Name of
|
||||||
"state" when Args == [] -> Icode1#{ state_type => ast_typerep(Def, Icode) };
|
"state" when Args == [] -> Icode1#{ state_type => ast_typerep(Def, Icode) };
|
||||||
"state" -> gen_error(state_type_cannot_be_parameterized);
|
"state" -> gen_error({parameterized_state, Id});
|
||||||
"event" when Args == [] -> Icode1#{ event_type => Def };
|
"event" when Args == [] -> Icode1#{ event_type => Def };
|
||||||
"event" -> gen_error(event_type_cannot_be_parameterized);
|
"event" -> gen_error({parameterized_event, Id});
|
||||||
_ -> Icode1
|
_ -> Icode1
|
||||||
end,
|
end,
|
||||||
contract_to_icode(Rest, Icode2);
|
contract_to_icode(Rest, Icode2);
|
||||||
@ -398,10 +398,8 @@ ast_binop(Op, Ann, {typed, _, A, Type}, B, Icode)
|
|||||||
when Op == '=='; Op == '!=';
|
when Op == '=='; Op == '!=';
|
||||||
Op == '<'; Op == '>';
|
Op == '<'; Op == '>';
|
||||||
Op == '<='; Op == '=<'; Op == '>=' ->
|
Op == '<='; Op == '=<'; Op == '>=' ->
|
||||||
Monomorphic = is_monomorphic(Type),
|
[ gen_error({cant_compare_type_aevm, Ann, Op, Type}) || not is_simple_type(Type) ],
|
||||||
case ast_typerep(Type, Icode) of
|
case ast_typerep(Type, Icode) of
|
||||||
_ when not Monomorphic ->
|
|
||||||
gen_error({cant_compare_polymorphic_type, Ann, Op, Type});
|
|
||||||
word -> #binop{op = Op, left = ast_body(A, Icode), right = ast_body(B, Icode)};
|
word -> #binop{op = Op, left = ast_body(A, Icode), right = ast_body(B, Icode)};
|
||||||
OtherType ->
|
OtherType ->
|
||||||
Neg = case Op of
|
Neg = case Op of
|
||||||
@ -767,14 +765,22 @@ map_upd(Key, Default, ValFun, Map = {typed, Ann, _, MapType}, Icode) ->
|
|||||||
builtin_call(FunName, Args).
|
builtin_call(FunName, Args).
|
||||||
|
|
||||||
check_entrypoint_type(Ann, Name, Args, Ret) ->
|
check_entrypoint_type(Ann, Name, Args, Ret) ->
|
||||||
Check = fun(T, Err) ->
|
CheckFirstOrder = fun(T, Err) ->
|
||||||
case is_simple_type(T) of
|
case is_first_order_type(T) of
|
||||||
false -> gen_error(Err);
|
false -> gen_error(Err);
|
||||||
true -> ok
|
true -> ok
|
||||||
end end,
|
end end,
|
||||||
[ Check(T, {entrypoint_argument_must_have_simple_type, Ann1, Name, X, T})
|
CheckMonomorphic = fun(T, Err) ->
|
||||||
|
case is_monomorphic(T) of
|
||||||
|
false -> gen_error(Err);
|
||||||
|
true -> ok
|
||||||
|
end end,
|
||||||
|
[ CheckFirstOrder(T, {entrypoint_argument_must_have_first_order_type, Ann1, Name, X, T})
|
||||||
|| {arg, Ann1, X, T} <- Args ],
|
|| {arg, Ann1, X, T} <- Args ],
|
||||||
Check(Ret, {entrypoint_must_have_simple_return_type, Ann, Name, Ret}).
|
CheckFirstOrder(Ret, {entrypoint_must_have_first_order_return_type, Ann, Name, Ret}),
|
||||||
|
[ CheckMonomorphic(T, {entrypoint_argument_must_have_monomorphic_type, Ann1, Name, X, T})
|
||||||
|
|| {arg, Ann1, X, T} <- Args ],
|
||||||
|
CheckMonomorphic(Ret, {entrypoint_must_have_monomorphic_return_type, Ann, Name, Ret}).
|
||||||
|
|
||||||
is_simple_type({tvar, _, _}) -> false;
|
is_simple_type({tvar, _, _}) -> false;
|
||||||
is_simple_type({fun_t, _, _, _, _}) -> false;
|
is_simple_type({fun_t, _, _, _, _}) -> false;
|
||||||
@ -782,6 +788,11 @@ is_simple_type(Ts) when is_list(Ts) -> lists:all(fun is_simple_type/1, Ts);
|
|||||||
is_simple_type(T) when is_tuple(T) -> is_simple_type(tuple_to_list(T));
|
is_simple_type(T) when is_tuple(T) -> is_simple_type(tuple_to_list(T));
|
||||||
is_simple_type(_) -> true.
|
is_simple_type(_) -> true.
|
||||||
|
|
||||||
|
is_first_order_type({fun_t, _, _, _, _}) -> false;
|
||||||
|
is_first_order_type(Ts) when is_list(Ts) -> lists:all(fun is_first_order_type/1, Ts);
|
||||||
|
is_first_order_type(T) when is_tuple(T) -> is_first_order_type(tuple_to_list(T));
|
||||||
|
is_first_order_type(_) -> true.
|
||||||
|
|
||||||
is_monomorphic({tvar, _, _}) -> false;
|
is_monomorphic({tvar, _, _}) -> false;
|
||||||
is_monomorphic([H|T]) ->
|
is_monomorphic([H|T]) ->
|
||||||
is_monomorphic(H) andalso is_monomorphic(T);
|
is_monomorphic(H) andalso is_monomorphic(T);
|
||||||
|
75
src/aeso_code_errors.erl
Normal file
75
src/aeso_code_errors.erl
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @author Ulf Norell
|
||||||
|
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||||
|
%%% @doc
|
||||||
|
%%% Formatting of code generation errors.
|
||||||
|
%%% @end
|
||||||
|
%%%
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
-module(aeso_code_errors).
|
||||||
|
|
||||||
|
-export([format/1]).
|
||||||
|
|
||||||
|
format({last_declaration_must_be_contract, Decl = {namespace, _, {con, _, C}, _}}) ->
|
||||||
|
Msg = io_lib:format("Expected a contract as the last declaration instead of the namespace '~s'\n",
|
||||||
|
[C]),
|
||||||
|
mk_err(pos(Decl), Msg);
|
||||||
|
format({missing_init_function, Con}) ->
|
||||||
|
Msg = io_lib:format("Missing init function for the contract '~s'.\n", [pp_expr(Con)]),
|
||||||
|
Cxt = "The 'init' function can only be omitted if the state type is 'unit'.\n",
|
||||||
|
mk_err(pos(Con), Msg, Cxt);
|
||||||
|
format({parameterized_state, Decl}) ->
|
||||||
|
Msg = "The state type cannot be parameterized.\n",
|
||||||
|
mk_err(pos(Decl), Msg);
|
||||||
|
format({parameterized_event, Decl}) ->
|
||||||
|
Msg = "The event type cannot be parameterized.\n",
|
||||||
|
mk_err(pos(Decl), Msg);
|
||||||
|
format({entrypoint_argument_must_have_monomorphic_type, Ann, {id, _, Name}, X, T}) ->
|
||||||
|
Msg = io_lib:format("The argument\n~s\nof entrypoint '~s' does not have a monomorphic type.\n",
|
||||||
|
[pp_typed(X, T), Name]),
|
||||||
|
Cxt = "Use the FATE backend if you want polymorphic entrypoints.",
|
||||||
|
mk_err(pos(Ann), Msg, Cxt);
|
||||||
|
format({cant_compare_type_aevm, Ann, Op, Type}) ->
|
||||||
|
StringAndTuple = [ "- type string\n"
|
||||||
|
"- tuple or record of word type\n" || lists:member(Op, ['==', '!=']) ],
|
||||||
|
Msg = io_lib:format("Cannot compare values of type\n"
|
||||||
|
"~s\n"
|
||||||
|
"The AEVM only supports '~s' on values of\n"
|
||||||
|
"- word type (int, bool, bits, address, oracle(_, _), etc)\n"
|
||||||
|
"~s"
|
||||||
|
"Use FATE if you need to compare arbitrary types.\n",
|
||||||
|
[pp_type(2, Type), Op, StringAndTuple]),
|
||||||
|
mk_err(pos(Ann), Msg);
|
||||||
|
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).\n",
|
||||||
|
[pp_type(2, T)]),
|
||||||
|
mk_err(pos(Ann), Msg);
|
||||||
|
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) ->
|
||||||
|
prettypr:format(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)).
|
||||||
|
|
@ -98,15 +98,7 @@ from_string(Backend, ContractString, Options) ->
|
|||||||
try
|
try
|
||||||
from_string1(Backend, ContractString, Options)
|
from_string1(Backend, ContractString, Options)
|
||||||
catch
|
catch
|
||||||
%% The compiler errors.
|
throw:{error, Errors} -> {error, Errors}
|
||||||
throw:{parse_errors, Errors} ->
|
|
||||||
{error, Errors};
|
|
||||||
throw:{type_errors, Errors} ->
|
|
||||||
{error, Errors};
|
|
||||||
error:{code_errors, Errors} ->
|
|
||||||
{error, join_errors("Code errors", Errors,
|
|
||||||
fun (E) -> io_lib:format("~p", [E]) end)}
|
|
||||||
%% General programming errors in the compiler just signal error.
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
from_string1(aevm, ContractString, Options) ->
|
from_string1(aevm, ContractString, Options) ->
|
||||||
@ -230,16 +222,10 @@ check_call1(ContractString0, FunName, Args, Options) ->
|
|||||||
{ok, FunName, CallArgs}
|
{ok, FunName, CallArgs}
|
||||||
end
|
end
|
||||||
catch
|
catch
|
||||||
throw:{parse_errors, Errors} ->
|
throw:{error, Errors} -> {error, Errors};
|
||||||
{error, Errors};
|
|
||||||
throw:{type_errors, Errors} ->
|
|
||||||
{error, Errors};
|
|
||||||
error:{badmatch, {error, missing_call_function}} ->
|
error:{badmatch, {error, missing_call_function}} ->
|
||||||
{error, join_errors("Type errors", ["missing __call function"],
|
{error, join_errors("Type errors", ["missing __call function"],
|
||||||
fun (E) -> E end)};
|
fun (E) -> E end)}
|
||||||
throw:Error -> %Don't ask
|
|
||||||
{error, join_errors("Code errors", [Error],
|
|
||||||
fun (E) -> io_lib:format("~p", [E]) end)}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
arguments_of_body(CallName, _FunName, Fcode) ->
|
arguments_of_body(CallName, _FunName, Fcode) ->
|
||||||
@ -345,16 +331,10 @@ to_sophia_value(ContractString, FunName, ok, Data, Options0) ->
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
catch
|
catch
|
||||||
throw:{parse_errors, Errors} ->
|
throw:{error, Errors} -> {error, Errors};
|
||||||
{error, Errors};
|
|
||||||
throw:{type_errors, Errors} ->
|
|
||||||
{error, Errors};
|
|
||||||
error:{badmatch, {error, missing_function}} ->
|
error:{badmatch, {error, missing_function}} ->
|
||||||
{error, join_errors("Type errors", ["no function: '" ++ FunName ++ "'"],
|
{error, join_errors("Type errors", ["no function: '" ++ FunName ++ "'"],
|
||||||
fun (E) -> E end)};
|
fun (E) -> E end)}
|
||||||
throw:Error -> %Don't ask
|
|
||||||
{error, join_errors("Code errors", [Error],
|
|
||||||
fun (E) -> io_lib:format("~p", [E]) end)}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
@ -444,16 +424,11 @@ decode_calldata(ContractString, FunName, Calldata, Options0) ->
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
catch
|
catch
|
||||||
throw:{parse_errors, Errors} ->
|
throw:{error, Errors} ->
|
||||||
{error, Errors};
|
|
||||||
throw:{type_errors, Errors} ->
|
|
||||||
{error, Errors};
|
{error, Errors};
|
||||||
error:{badmatch, {error, missing_function}} ->
|
error:{badmatch, {error, missing_function}} ->
|
||||||
{error, join_errors("Type errors", ["no function: '" ++ FunName ++ "'"],
|
{error, join_errors("Type errors", ["no function: '" ++ FunName ++ "'"],
|
||||||
fun (E) -> E end)};
|
fun (E) -> E end)}
|
||||||
throw:Error -> %Don't ask
|
|
||||||
{error, join_errors("Code errors", [Error],
|
|
||||||
fun (E) -> io_lib:format("~p", [E]) end)}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_arg_icode(Funs) ->
|
get_arg_icode(Funs) ->
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
, pos/2
|
, pos/2
|
||||||
, pos/3
|
, pos/3
|
||||||
, pp/1
|
, pp/1
|
||||||
|
, throw/1
|
||||||
, type/1
|
, type/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
@ -49,6 +50,12 @@ pos(Line, Col) ->
|
|||||||
pos(File, Line, Col) ->
|
pos(File, Line, Col) ->
|
||||||
#pos{ file = File, line = Line, col = Col }.
|
#pos{ file = File, line = Line, col = Col }.
|
||||||
|
|
||||||
|
throw([]) -> ok;
|
||||||
|
throw(Errs) when is_list(Errs) ->
|
||||||
|
erlang:throw({error, Errs});
|
||||||
|
throw(#err{} = Err) ->
|
||||||
|
erlang:throw({error, [Err]}).
|
||||||
|
|
||||||
msg(#err{ message = Msg, context = none }) -> Msg;
|
msg(#err{ message = Msg, context = none }) -> Msg;
|
||||||
msg(#err{ message = Msg, context = Ctxt }) -> Msg ++ Ctxt.
|
msg(#err{ message = Msg, context = Ctxt }) -> Msg ++ Ctxt.
|
||||||
|
|
||||||
@ -68,4 +75,4 @@ pp(#err{ pos = Pos } = Err) ->
|
|||||||
pp_pos(#pos{file = no_file, line = L, col = C}) ->
|
pp_pos(#pos{file = no_file, line = L, col = C}) ->
|
||||||
io_lib:format("At line ~p, col ~p:", [L, C]);
|
io_lib:format("At line ~p, col ~p:", [L, C]);
|
||||||
pp_pos(#pos{file = F, line = L, col = C}) ->
|
pp_pos(#pos{file = F, line = L, col = C}) ->
|
||||||
io_lib:format("In '~s' at line ~p, col~p:", [F, L, C]).
|
io_lib:format("In '~s' at line ~p, col ~p:", [F, L, C]).
|
||||||
|
@ -33,10 +33,10 @@ string(String, Included, Opts) ->
|
|||||||
{ok, AST} ->
|
{ok, AST} ->
|
||||||
case expand_includes(AST, Included, Opts) of
|
case expand_includes(AST, Included, Opts) of
|
||||||
{ok, AST1} -> AST1;
|
{ok, AST1} -> AST1;
|
||||||
{error, Err} -> throw({parse_errors, [mk_error(Err)]})
|
{error, Err} -> aeso_errors:throw(mk_error(Err))
|
||||||
end;
|
end;
|
||||||
{error, Err} ->
|
{error, Err} ->
|
||||||
throw({parse_errors, [mk_error(Err)]})
|
aeso_errors:throw(mk_error(Err))
|
||||||
end.
|
end.
|
||||||
|
|
||||||
type(String) ->
|
type(String) ->
|
||||||
|
@ -163,7 +163,7 @@ permissive_literals_fail_test() ->
|
|||||||
" Chain.spend(o, 1000000)\n",
|
" Chain.spend(o, 1000000)\n",
|
||||||
{error, [Err]} =
|
{error, [Err]} =
|
||||||
aeso_compiler:check_call(Contract, "haxx", ["#123"], []),
|
aeso_compiler:check_call(Contract, "haxx", ["#123"], []),
|
||||||
?assertMatch("Cannot unify" ++ _, aeso_errors:pp(Err)),
|
?assertMatch("At line 3, col 5:\nCannot unify" ++ _, aeso_errors:pp(Err)),
|
||||||
?assertEqual(type_error, aeso_errors:type(Err)),
|
?assertEqual(type_error, aeso_errors:type(Err)),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
@ -16,57 +16,74 @@
|
|||||||
%% are made on the output, just that it is a binary which indicates
|
%% are made on the output, just that it is a binary which indicates
|
||||||
%% that the compilation worked.
|
%% that the compilation worked.
|
||||||
simple_compile_test_() ->
|
simple_compile_test_() ->
|
||||||
[ {"Testing the " ++ ContractName ++ " contract with the " ++ atom_to_list(Backend) ++ " backend",
|
[ {"Testing the " ++ ContractName ++ " contract with the " ++ atom_to_list(Backend) ++ " backend",
|
||||||
fun() ->
|
fun() ->
|
||||||
case compile(Backend, ContractName) of
|
case compile(Backend, ContractName) of
|
||||||
#{byte_code := ByteCode,
|
#{byte_code := ByteCode,
|
||||||
contract_source := _,
|
contract_source := _,
|
||||||
type_info := _} when Backend == aevm ->
|
type_info := _} when Backend == aevm ->
|
||||||
?assertMatch(Code when is_binary(Code), ByteCode);
|
?assertMatch(Code when is_binary(Code), ByteCode);
|
||||||
#{fate_code := Code} when Backend == fate ->
|
#{fate_code := Code} when Backend == fate ->
|
||||||
Code1 = aeb_fate_code:deserialize(aeb_fate_code:serialize(Code)),
|
Code1 = aeb_fate_code:deserialize(aeb_fate_code:serialize(Code)),
|
||||||
?assertMatch({X, X}, {Code1, Code});
|
?assertMatch({X, X}, {Code1, Code});
|
||||||
ErrBin ->
|
ErrBin ->
|
||||||
io:format("\n~s", [ErrBin]),
|
io:format("\n~s", [ErrBin]),
|
||||||
error(ErrBin)
|
error(ErrBin)
|
||||||
end
|
end
|
||||||
end} || ContractName <- compilable_contracts(), Backend <- [aevm, fate],
|
end} || ContractName <- compilable_contracts(), Backend <- [aevm, fate],
|
||||||
not lists:member(ContractName, not_yet_compilable(Backend))] ++
|
not lists:member(ContractName, not_yet_compilable(Backend))] ++
|
||||||
[ {"Testing error messages of " ++ ContractName,
|
[ {"Testing error messages of " ++ ContractName,
|
||||||
fun() ->
|
fun() ->
|
||||||
case compile(aevm, ContractName) of
|
Errors = compile(aevm, ContractName),
|
||||||
<<"Parse errors\n", ErrorString/binary>> ->
|
check_errors(ExpectedErrors, Errors)
|
||||||
check_errors(lists:sort(ExpectedErrors), ErrorString);
|
end} ||
|
||||||
Errors ->
|
{ContractName, ExpectedErrors} <- failing_contracts() ] ++
|
||||||
check_errors(lists:sort(ExpectedErrors), Errors)
|
[ {"Testing " ++ atom_to_list(Backend) ++ " code generation error messages of " ++ ContractName,
|
||||||
end
|
fun() ->
|
||||||
end} ||
|
Errors = compile(Backend, ContractName),
|
||||||
{ContractName, ExpectedErrors} <- failing_contracts() ] ++
|
Expect =
|
||||||
[ {"Testing include with explicit files",
|
case is_binary(ExpectedError) of
|
||||||
fun() ->
|
true -> [ExpectedError];
|
||||||
FileSystem = maps:from_list(
|
false ->
|
||||||
[ begin
|
case proplists:get_value(Backend, ExpectedError, no_error) of
|
||||||
{ok, Bin} = file:read_file(filename:join([aeso_test_utils:contract_path(), File])),
|
no_error -> no_error;
|
||||||
{File, Bin}
|
Err -> [Err]
|
||||||
end || File <- ["included.aes", "../contracts/included2.aes"] ]),
|
end
|
||||||
#{byte_code := Code1} = compile(aevm, "include", [{include, {explicit_files, FileSystem}}]),
|
end,
|
||||||
#{byte_code := Code2} = compile(aevm, "include"),
|
check_errors(Expect, Errors)
|
||||||
?assertMatch(true, Code1 == Code2)
|
end} ||
|
||||||
end} ] ++
|
{ContractName, ExpectedError} <- failing_code_gen_contracts(),
|
||||||
[ {"Testing deadcode elimination for " ++ atom_to_list(Backend),
|
Backend <- [aevm, fate] ] ++
|
||||||
fun() ->
|
[ {"Testing include with explicit files",
|
||||||
#{ byte_code := NoDeadCode } = compile(Backend, "nodeadcode"),
|
fun() ->
|
||||||
#{ byte_code := DeadCode } = compile(Backend, "deadcode"),
|
FileSystem = maps:from_list(
|
||||||
SizeNoDeadCode = byte_size(NoDeadCode),
|
[ begin
|
||||||
SizeDeadCode = byte_size(DeadCode),
|
{ok, Bin} = file:read_file(filename:join([aeso_test_utils:contract_path(), File])),
|
||||||
Delta = if Backend == aevm -> 40;
|
{File, Bin}
|
||||||
Backend == fate -> 20 end,
|
end || File <- ["included.aes", "../contracts/included2.aes"] ]),
|
||||||
?assertMatch({_, _, true}, {SizeDeadCode, SizeNoDeadCode, SizeDeadCode + Delta < SizeNoDeadCode}),
|
#{byte_code := Code1} = compile(aevm, "include", [{include, {explicit_files, FileSystem}}]),
|
||||||
ok
|
#{byte_code := Code2} = compile(aevm, "include"),
|
||||||
end} || Backend <- [aevm, fate] ].
|
?assertMatch(true, Code1 == Code2)
|
||||||
|
end} ] ++
|
||||||
|
[ {"Testing deadcode elimination for " ++ atom_to_list(Backend),
|
||||||
|
fun() ->
|
||||||
|
#{ byte_code := NoDeadCode } = compile(Backend, "nodeadcode"),
|
||||||
|
#{ byte_code := DeadCode } = compile(Backend, "deadcode"),
|
||||||
|
SizeNoDeadCode = byte_size(NoDeadCode),
|
||||||
|
SizeDeadCode = byte_size(DeadCode),
|
||||||
|
Delta = if Backend == aevm -> 40;
|
||||||
|
Backend == fate -> 20 end,
|
||||||
|
?assertMatch({_, _, true}, {SizeDeadCode, SizeNoDeadCode, SizeDeadCode + Delta < SizeNoDeadCode}),
|
||||||
|
ok
|
||||||
|
end} || Backend <- [aevm, fate] ] ++
|
||||||
|
[].
|
||||||
|
|
||||||
check_errors(Expect, Actual0) ->
|
check_errors(no_error, Actual) -> ?assertMatch(#{}, Actual);
|
||||||
Actual = [ list_to_binary(string:trim(aeso_errors:msg(Err))) || Err <- Actual0 ],
|
check_errors(Expect, #{}) ->
|
||||||
|
?assertEqual({error, Expect}, ok);
|
||||||
|
check_errors(Expect0, Actual0) ->
|
||||||
|
Expect = lists:sort(Expect0),
|
||||||
|
Actual = [ list_to_binary(string:trim(aeso_errors:pp(Err))) || Err <- Actual0 ],
|
||||||
case {Expect -- Actual, Actual -- Expect} of
|
case {Expect -- Actual, Actual -- Expect} of
|
||||||
{[], Extra} -> ?assertMatch({unexpected, []}, {unexpected, Extra});
|
{[], Extra} -> ?assertMatch({unexpected, []}, {unexpected, Extra});
|
||||||
{Missing, []} -> ?assertMatch({missing, []}, {missing, Missing});
|
{Missing, []} -> ?assertMatch({missing, []}, {missing, Missing});
|
||||||
@ -79,7 +96,7 @@ compile(Backend, Name) ->
|
|||||||
|
|
||||||
compile(Backend, Name, Options) ->
|
compile(Backend, Name, Options) ->
|
||||||
String = aeso_test_utils:read_contract(Name),
|
String = aeso_test_utils:read_contract(Name),
|
||||||
case aeso_compiler:from_string(String, [{src_file, Name}, {backend, Backend} | Options]) of
|
case aeso_compiler:from_string(String, [{src_file, Name ++ ".aes"}, {backend, Backend} | Options]) of
|
||||||
{ok, Map} -> Map;
|
{ok, Map} -> Map;
|
||||||
{error, ErrorString} when is_binary(ErrorString) -> ErrorString;
|
{error, ErrorString} when is_binary(ErrorString) -> ErrorString;
|
||||||
{error, Errors} -> Errors
|
{error, Errors} -> Errors
|
||||||
@ -135,241 +152,370 @@ not_yet_compilable(aevm) -> [].
|
|||||||
|
|
||||||
%% Contracts that should produce type errors
|
%% Contracts that should produce type errors
|
||||||
|
|
||||||
|
-define(Pos(Line, Col), "At line " ??Line ", col " ??Col ":\n").
|
||||||
|
-define(Pos(File, Line, Col), "In '" File ".aes' at line " ??Line ", col " ??Col ":\n").
|
||||||
|
|
||||||
failing_contracts() ->
|
failing_contracts() ->
|
||||||
[ {"name_clash",
|
[ {"name_clash",
|
||||||
[<<"Duplicate definitions of abort at\n"
|
[<<?Pos(14, 3)
|
||||||
|
"Duplicate definitions of abort at\n"
|
||||||
" - (builtin location)\n"
|
" - (builtin location)\n"
|
||||||
" - line 14, column 3">>,
|
" - line 14, column 3">>,
|
||||||
<<"Duplicate definitions of require at\n"
|
<<?Pos(15, 3)
|
||||||
|
"Duplicate definitions of require at\n"
|
||||||
" - (builtin location)\n"
|
" - (builtin location)\n"
|
||||||
" - line 15, column 3">>,
|
" - line 15, column 3">>,
|
||||||
<<"Duplicate definitions of double_def at\n"
|
<<?Pos(11, 3)
|
||||||
|
"Duplicate definitions of double_def at\n"
|
||||||
" - line 10, column 3\n"
|
" - line 10, column 3\n"
|
||||||
" - line 11, column 3">>,
|
" - line 11, column 3">>,
|
||||||
<<"Duplicate definitions of double_proto at\n"
|
<<?Pos(5, 3)
|
||||||
|
"Duplicate definitions of double_proto at\n"
|
||||||
" - line 4, column 3\n"
|
" - line 4, column 3\n"
|
||||||
" - line 5, column 3">>,
|
" - line 5, column 3">>,
|
||||||
<<"Duplicate definitions of proto_and_def at\n"
|
<<?Pos(8, 3)
|
||||||
|
"Duplicate definitions of proto_and_def at\n"
|
||||||
" - line 7, column 3\n"
|
" - line 7, column 3\n"
|
||||||
" - line 8, column 3">>,
|
" - line 8, column 3">>,
|
||||||
<<"Duplicate definitions of put at\n"
|
<<?Pos(16, 3)
|
||||||
|
"Duplicate definitions of put at\n"
|
||||||
" - (builtin location)\n"
|
" - (builtin location)\n"
|
||||||
" - line 16, column 3">>,
|
" - line 16, column 3">>,
|
||||||
<<"Duplicate definitions of state at\n"
|
<<?Pos(17, 3)
|
||||||
|
"Duplicate definitions of state at\n"
|
||||||
" - (builtin location)\n"
|
" - (builtin location)\n"
|
||||||
" - line 17, column 3">>]}
|
" - line 17, column 3">>]}
|
||||||
, {"type_errors",
|
, {"type_errors",
|
||||||
[<<"Unbound variable zz at line 17, column 23">>,
|
[<<?Pos(17, 23)
|
||||||
<<"Cannot unify int\n"
|
"Unbound variable zz at line 17, column 23">>,
|
||||||
|
<<?Pos(26, 9)
|
||||||
|
"Cannot unify int\n"
|
||||||
" and list(int)\n"
|
" and list(int)\n"
|
||||||
"when checking the application at line 26, column 9 of\n"
|
"when checking the application at line 26, column 9 of\n"
|
||||||
" (::) : (int, list(int)) => list(int)\n"
|
" (::) : (int, list(int)) => list(int)\n"
|
||||||
"to arguments\n"
|
"to arguments\n"
|
||||||
" x : int\n"
|
" x : int\n"
|
||||||
" x : int">>,
|
" x : int">>,
|
||||||
<<"Cannot unify string\n"
|
<<?Pos(9, 48)
|
||||||
|
"Cannot unify string\n"
|
||||||
" and int\n"
|
" and int\n"
|
||||||
"when checking the assignment of the field\n"
|
"when checking the assignment of the field\n"
|
||||||
" x : map(string, string) (at line 9, column 48)\n"
|
" x : map(string, string) (at line 9, column 48)\n"
|
||||||
"to the old value __x and the new value\n"
|
"to the old value __x and the new value\n"
|
||||||
" __x {[\"foo\"] @ x = x + 1} : map(string, int)">>,
|
" __x {[\"foo\"] @ x = x + 1} : map(string, int)">>,
|
||||||
<<"Cannot unify int\n"
|
<<?Pos(34, 47)
|
||||||
|
"Cannot unify int\n"
|
||||||
" and string\n"
|
" and string\n"
|
||||||
"when checking the type of the expression at line 34, column 47\n"
|
"when checking the type of the expression at line 34, column 47\n"
|
||||||
" 1 : int\n"
|
" 1 : int\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" string">>,
|
" string">>,
|
||||||
<<"Cannot unify string\n"
|
<<?Pos(34, 52)
|
||||||
|
"Cannot unify string\n"
|
||||||
" and int\n"
|
" and int\n"
|
||||||
"when checking the type of the expression at line 34, column 52\n"
|
"when checking the type of the expression at line 34, column 52\n"
|
||||||
" \"bla\" : string\n"
|
" \"bla\" : string\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" int">>,
|
" int">>,
|
||||||
<<"Cannot unify string\n"
|
<<?Pos(32, 18)
|
||||||
|
"Cannot unify string\n"
|
||||||
" and int\n"
|
" and int\n"
|
||||||
"when checking the type of the expression at line 32, column 18\n"
|
"when checking the type of the expression at line 32, column 18\n"
|
||||||
" \"x\" : string\n"
|
" \"x\" : string\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" int">>,
|
" int">>,
|
||||||
<<"Cannot unify string\n"
|
<<?Pos(11, 58)
|
||||||
|
"Cannot unify string\n"
|
||||||
" and int\n"
|
" and int\n"
|
||||||
"when checking the type of the expression at line 11, column 58\n"
|
"when checking the type of the expression at line 11, column 58\n"
|
||||||
" \"foo\" : string\n"
|
" \"foo\" : string\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" int">>,
|
" int">>,
|
||||||
<<"Cannot unify int\n"
|
<<?Pos(38, 13)
|
||||||
|
"Cannot unify int\n"
|
||||||
" and string\n"
|
" and string\n"
|
||||||
"when comparing the types of the if-branches\n"
|
"when comparing the types of the if-branches\n"
|
||||||
" - w : int (at line 38, column 13)\n"
|
" - w : int (at line 38, column 13)\n"
|
||||||
" - z : string (at line 39, column 10)">>,
|
" - z : string (at line 39, column 10)">>,
|
||||||
<<"Not a record type: string\n"
|
<<?Pos(22, 40)
|
||||||
|
"Not a record type: string\n"
|
||||||
"arising from the projection of the field y (at line 22, column 40)">>,
|
"arising from the projection of the field y (at line 22, column 40)">>,
|
||||||
<<"Not a record type: string\n"
|
<<?Pos(21, 44)
|
||||||
|
"Not a record type: string\n"
|
||||||
"arising from an assignment of the field y (at line 21, column 44)">>,
|
"arising from an assignment of the field y (at line 21, column 44)">>,
|
||||||
<<"Not a record type: string\n"
|
<<?Pos(20, 40)
|
||||||
|
"Not a record type: string\n"
|
||||||
"arising from an assignment of the field y (at line 20, column 40)">>,
|
"arising from an assignment of the field y (at line 20, column 40)">>,
|
||||||
<<"Not a record type: string\n"
|
<<?Pos(19, 37)
|
||||||
|
"Not a record type: string\n"
|
||||||
"arising from an assignment of the field y (at line 19, column 37)">>,
|
"arising from an assignment of the field y (at line 19, column 37)">>,
|
||||||
<<"Ambiguous record type with field y (at line 13, column 27) could be one of\n"
|
<<?Pos(13, 27)
|
||||||
|
"Ambiguous record type with field y (at line 13, column 27) could be one of\n"
|
||||||
" - r (at line 4, column 10)\n"
|
" - r (at line 4, column 10)\n"
|
||||||
" - r' (at line 5, column 10)">>,
|
" - r' (at line 5, column 10)">>,
|
||||||
<<"Repeated name x in pattern\n"
|
<<?Pos(26, 7)
|
||||||
|
"Repeated name x in pattern\n"
|
||||||
" x :: x (at line 26, column 7)">>,
|
" x :: x (at line 26, column 7)">>,
|
||||||
<<"Repeated argument x to function repeated_arg (at line 44, column 14).">>,
|
<<?Pos(44, 14)
|
||||||
<<"Repeated argument y to function repeated_arg (at line 44, column 14).">>,
|
"Repeated argument x to function repeated_arg (at line 44, column 14).">>,
|
||||||
<<"No record type with fields y, z (at line 14, column 24)">>,
|
<<?Pos(44, 14)
|
||||||
<<"The field z is missing when constructing an element of type r2 (at line 15, column 26)">>,
|
"Repeated argument y to function repeated_arg (at line 44, column 14).">>,
|
||||||
<<"Record type r2 does not have field y (at line 15, column 24)">>,
|
<<?Pos(14, 24)
|
||||||
<<"Let binding at line 47, column 5 must be followed by an expression">>,
|
"No record type with fields y, z (at line 14, column 24)">>,
|
||||||
<<"Let binding at line 50, column 5 must be followed by an expression">>,
|
<<?Pos(15, 26)
|
||||||
<<"Let binding at line 54, column 5 must be followed by an expression">>,
|
"The field z is missing when constructing an element of type r2 (at line 15, column 26)">>,
|
||||||
<<"Let binding at line 58, column 5 must be followed by an expression">>]}
|
<<?Pos(15, 24)
|
||||||
|
"Record type r2 does not have field y (at line 15, column 24)">>,
|
||||||
|
<<?Pos(47, 5)
|
||||||
|
"Let binding at line 47, column 5 must be followed by an expression">>,
|
||||||
|
<<?Pos(50, 5)
|
||||||
|
"Let binding at line 50, column 5 must be followed by an expression">>,
|
||||||
|
<<?Pos(54, 5)
|
||||||
|
"Let binding at line 54, column 5 must be followed by an expression">>,
|
||||||
|
<<?Pos(58, 5)
|
||||||
|
"Let binding at line 58, column 5 must be followed by an expression">>]}
|
||||||
, {"init_type_error",
|
, {"init_type_error",
|
||||||
[<<"Cannot unify string\n"
|
[<<?Pos(7, 3)
|
||||||
|
"Cannot unify string\n"
|
||||||
" and map(int, int)\n"
|
" and map(int, int)\n"
|
||||||
"when checking that 'init' returns a value of type 'state' at line 7, column 3">>]}
|
"when checking that 'init' returns a value of type 'state' at line 7, column 3">>]}
|
||||||
, {"missing_state_type",
|
, {"missing_state_type",
|
||||||
[<<"Cannot unify string\n"
|
[<<?Pos(5, 3)
|
||||||
|
"Cannot unify string\n"
|
||||||
" and unit\n"
|
" and unit\n"
|
||||||
"when checking that 'init' returns a value of type 'state' at line 5, column 3">>]}
|
"when checking that 'init' returns a value of type 'state' at line 5, column 3">>]}
|
||||||
, {"missing_fields_in_record_expression",
|
, {"missing_fields_in_record_expression",
|
||||||
[<<"The field x is missing when constructing an element of type r('a) (at line 7, column 42)">>,
|
[<<?Pos(7, 42)
|
||||||
<<"The field y is missing when constructing an element of type r(int) (at line 8, column 42)">>,
|
"The field x is missing when constructing an element of type r('a) (at line 7, column 42)">>,
|
||||||
<<"The fields y, z are missing when constructing an element of type r('a) (at line 6, column 42)">>]}
|
<<?Pos(8, 42)
|
||||||
|
"The field y is missing when constructing an element of type r(int) (at line 8, column 42)">>,
|
||||||
|
<<?Pos(6, 42)
|
||||||
|
"The fields y, z are missing when constructing an element of type r('a) (at line 6, column 42)">>]}
|
||||||
, {"namespace_clash",
|
, {"namespace_clash",
|
||||||
[<<"The contract Call (at line 4, column 10) has the same name as a namespace at (builtin location)">>]}
|
[<<?Pos(4, 10)
|
||||||
|
"The contract Call (at line 4, column 10) has the same name as a namespace at (builtin location)">>]}
|
||||||
, {"bad_events",
|
, {"bad_events",
|
||||||
[<<"The indexed type string (at line 9, column 25) is not a word type">>,
|
[<<?Pos(9, 25)
|
||||||
<<"The indexed type alias_string (at line 10, column 25) equals string which is not a word type">>]}
|
"The indexed type string (at line 9, column 25) is not a word type">>,
|
||||||
|
<<?Pos(10, 25)
|
||||||
|
"The indexed type alias_string (at line 10, column 25) equals string which is not a word type">>]}
|
||||||
, {"bad_events2",
|
, {"bad_events2",
|
||||||
[<<"The event constructor BadEvent1 (at line 9, column 7) has too many non-indexed values (max 1)">>,
|
[<<?Pos(9, 7)
|
||||||
<<"The event constructor BadEvent2 (at line 10, column 7) has too many indexed values (max 3)">>]}
|
"The event constructor BadEvent1 (at line 9, column 7) has too many non-indexed values (max 1)">>,
|
||||||
|
<<?Pos(10, 7)
|
||||||
|
"The event constructor BadEvent2 (at line 10, column 7) has too many indexed values (max 3)">>]}
|
||||||
, {"type_clash",
|
, {"type_clash",
|
||||||
[<<"Cannot unify int\n"
|
[<<?Pos(12, 42)
|
||||||
|
"Cannot unify int\n"
|
||||||
" and string\n"
|
" and string\n"
|
||||||
"when checking the record projection at line 12, column 42\n"
|
"when checking the record projection at line 12, column 42\n"
|
||||||
" r.foo : (gas : int, value : int) => Remote.themap\n"
|
" r.foo : (gas : int, value : int) => Remote.themap\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" (gas : int, value : int) => map(string, int)">>]}
|
" (gas : int, value : int) => map(string, int)">>]}
|
||||||
, {"bad_include_and_ns",
|
, {"bad_include_and_ns",
|
||||||
[<<"Include of 'included.aes' at line 2, column 11\nnot allowed, include only allowed at top level.">>,
|
[<<?Pos(2, 11)
|
||||||
<<"Nested namespace not allowed\nNamespace 'Foo' at line 3, column 13 not defined at top level.">>]}
|
"Include of 'included.aes' at line 2, column 11\nnot allowed, include only allowed at top level.">>,
|
||||||
|
<<?Pos(3, 13)
|
||||||
|
"Nested namespace not allowed\nNamespace 'Foo' at line 3, column 13 not defined at top level.">>]}
|
||||||
, {"bad_address_literals",
|
, {"bad_address_literals",
|
||||||
[<<"The type bytes(32) is not a contract type\n"
|
[<<?Pos(32, 5)
|
||||||
|
"The type bytes(32) is not a contract type\n"
|
||||||
"when checking that the contract literal at line 32, column 5\n"
|
"when checking that the contract literal at line 32, column 5\n"
|
||||||
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
||||||
"has the type\n"
|
"has the type\n"
|
||||||
" bytes(32)">>,
|
" bytes(32)">>,
|
||||||
<<"The type oracle(int, bool) is not a contract type\n"
|
<<?Pos(30, 5)
|
||||||
|
"The type oracle(int, bool) is not a contract type\n"
|
||||||
"when checking that the contract literal at line 30, column 5\n"
|
"when checking that the contract literal at line 30, column 5\n"
|
||||||
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
||||||
"has the type\n"
|
"has the type\n"
|
||||||
" oracle(int, bool)">>,
|
" oracle(int, bool)">>,
|
||||||
<<"The type address is not a contract type\n"
|
<<?Pos(28, 5)
|
||||||
|
"The type address is not a contract type\n"
|
||||||
"when checking that the contract literal at line 28, column 5\n"
|
"when checking that the contract literal at line 28, column 5\n"
|
||||||
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
||||||
"has the type\n"
|
"has the type\n"
|
||||||
" address">>,
|
" address">>,
|
||||||
<<"Cannot unify oracle_query('a, 'b)\n"
|
<<?Pos(25, 5)
|
||||||
|
"Cannot unify oracle_query('a, 'b)\n"
|
||||||
" and Remote\n"
|
" and Remote\n"
|
||||||
"when checking the type of the expression at line 25, column 5\n"
|
"when checking the type of the expression at line 25, column 5\n"
|
||||||
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
|
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
|
||||||
" oracle_query('a, 'b)\n"
|
" oracle_query('a, 'b)\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" Remote">>,
|
" Remote">>,
|
||||||
<<"Cannot unify oracle_query('c, 'd)\n"
|
<<?Pos(23, 5)
|
||||||
|
"Cannot unify oracle_query('c, 'd)\n"
|
||||||
" and bytes(32)\n"
|
" and bytes(32)\n"
|
||||||
"when checking the type of the expression at line 23, column 5\n"
|
"when checking the type of the expression at line 23, column 5\n"
|
||||||
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
|
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
|
||||||
" oracle_query('c, 'd)\n"
|
" oracle_query('c, 'd)\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" bytes(32)">>,
|
" bytes(32)">>,
|
||||||
<<"Cannot unify oracle_query('e, 'f)\n"
|
<<?Pos(21, 5)
|
||||||
|
"Cannot unify oracle_query('e, 'f)\n"
|
||||||
" and oracle(int, bool)\n"
|
" and oracle(int, bool)\n"
|
||||||
"when checking the type of the expression at line 21, column 5\n"
|
"when checking the type of the expression at line 21, column 5\n"
|
||||||
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
|
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
|
||||||
" oracle_query('e, 'f)\n"
|
" oracle_query('e, 'f)\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" oracle(int, bool)">>,
|
" oracle(int, bool)">>,
|
||||||
<<"Cannot unify oracle('g, 'h)\n"
|
<<?Pos(18, 5)
|
||||||
|
"Cannot unify oracle('g, 'h)\n"
|
||||||
" and Remote\n"
|
" and Remote\n"
|
||||||
"when checking the type of the expression at line 18, column 5\n"
|
"when checking the type of the expression at line 18, column 5\n"
|
||||||
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
|
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
|
||||||
" oracle('g, 'h)\n"
|
" oracle('g, 'h)\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" Remote">>,
|
" Remote">>,
|
||||||
<<"Cannot unify oracle('i, 'j)\n"
|
<<?Pos(16, 5)
|
||||||
|
"Cannot unify oracle('i, 'j)\n"
|
||||||
" and bytes(32)\n"
|
" and bytes(32)\n"
|
||||||
"when checking the type of the expression at line 16, column 5\n"
|
"when checking the type of the expression at line 16, column 5\n"
|
||||||
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
|
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
|
||||||
" oracle('i, 'j)\n"
|
" oracle('i, 'j)\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" bytes(32)">>,
|
" bytes(32)">>,
|
||||||
<<"Cannot unify oracle('k, 'l)\n"
|
<<?Pos(14, 5)
|
||||||
|
"Cannot unify oracle('k, 'l)\n"
|
||||||
" and oracle_query(int, bool)\n"
|
" and oracle_query(int, bool)\n"
|
||||||
"when checking the type of the expression at line 14, column 5\n"
|
"when checking the type of the expression at line 14, column 5\n"
|
||||||
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
|
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
|
||||||
" oracle('k, 'l)\n"
|
" oracle('k, 'l)\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" oracle_query(int, bool)">>,
|
" oracle_query(int, bool)">>,
|
||||||
<<"Cannot unify address\n"
|
<<?Pos(11, 5)
|
||||||
|
"Cannot unify address\n"
|
||||||
" and oracle(int, bool)\n"
|
" and oracle(int, bool)\n"
|
||||||
"when checking the type of the expression at line 11, column 5\n"
|
"when checking the type of the expression at line 11, column 5\n"
|
||||||
" ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address\n"
|
" ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" oracle(int, bool)">>,
|
" oracle(int, bool)">>,
|
||||||
<<"Cannot unify address\n"
|
<<?Pos(9, 5)
|
||||||
|
"Cannot unify address\n"
|
||||||
" and Remote\n"
|
" and Remote\n"
|
||||||
"when checking the type of the expression at line 9, column 5\n"
|
"when checking the type of the expression at line 9, column 5\n"
|
||||||
" ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address\n"
|
" ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" Remote">>,
|
" Remote">>,
|
||||||
<<"Cannot unify address\n"
|
<<?Pos(7, 5)
|
||||||
|
"Cannot unify address\n"
|
||||||
" and bytes(32)\n"
|
" and bytes(32)\n"
|
||||||
"when checking the type of the expression at line 7, column 5\n"
|
"when checking the type of the expression at line 7, column 5\n"
|
||||||
" ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address\n"
|
" ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" bytes(32)">>]}
|
" bytes(32)">>]}
|
||||||
, {"stateful",
|
, {"stateful",
|
||||||
[<<"Cannot reference stateful function Chain.spend (at line 13, column 35)\nin the definition of non-stateful function fail1.">>,
|
[<<?Pos(13, 35)
|
||||||
<<"Cannot reference stateful function local_spend (at line 14, column 35)\nin the definition of non-stateful function fail2.">>,
|
"Cannot reference stateful function Chain.spend (at line 13, column 35)\nin the definition of non-stateful function fail1.">>,
|
||||||
<<"Cannot reference stateful function Chain.spend (at line 16, column 15)\nin the definition of non-stateful function fail3.">>,
|
<<?Pos(14, 35)
|
||||||
<<"Cannot reference stateful function Chain.spend (at line 20, column 31)\nin the definition of non-stateful function fail4.">>,
|
"Cannot reference stateful function local_spend (at line 14, column 35)\nin the definition of non-stateful function fail2.">>,
|
||||||
<<"Cannot reference stateful function Chain.spend (at line 35, column 47)\nin the definition of non-stateful function fail5.">>,
|
<<?Pos(16, 15)
|
||||||
<<"Cannot pass non-zero value argument 1000 (at line 48, column 57)\nin the definition of non-stateful function fail6.">>,
|
"Cannot reference stateful function Chain.spend (at line 16, column 15)\nin the definition of non-stateful function fail3.">>,
|
||||||
<<"Cannot pass non-zero value argument 1000 (at line 49, column 56)\nin the definition of non-stateful function fail7.">>,
|
<<?Pos(20, 31)
|
||||||
<<"Cannot pass non-zero value argument 1000 (at line 52, column 17)\nin the definition of non-stateful function fail8.">>]}
|
"Cannot reference stateful function Chain.spend (at line 20, column 31)\nin the definition of non-stateful function fail4.">>,
|
||||||
|
<<?Pos(35, 47)
|
||||||
|
"Cannot reference stateful function Chain.spend (at line 35, column 47)\nin the definition of non-stateful function fail5.">>,
|
||||||
|
<<?Pos(48, 57)
|
||||||
|
"Cannot pass non-zero value argument 1000 (at line 48, column 57)\nin the definition of non-stateful function fail6.">>,
|
||||||
|
<<?Pos(49, 56)
|
||||||
|
"Cannot pass non-zero value argument 1000 (at line 49, column 56)\nin the definition of non-stateful function fail7.">>,
|
||||||
|
<<?Pos(52, 17)
|
||||||
|
"Cannot pass non-zero value argument 1000 (at line 52, column 17)\nin the definition of non-stateful function fail8.">>]}
|
||||||
, {"bad_init_state_access",
|
, {"bad_init_state_access",
|
||||||
[<<"The init function should return the initial state as its result and cannot write the state,\n"
|
[<<?Pos(11, 5)
|
||||||
|
"The init function should return the initial state as its result and cannot write the state,\n"
|
||||||
"but it calls\n"
|
"but it calls\n"
|
||||||
" - set_state (at line 11, column 5), which calls\n"
|
" - set_state (at line 11, column 5), which calls\n"
|
||||||
" - roundabout (at line 8, column 38), which calls\n"
|
" - roundabout (at line 8, column 38), which calls\n"
|
||||||
" - put (at line 7, column 39)">>,
|
" - put (at line 7, column 39)">>,
|
||||||
<<"The init function should return the initial state as its result and cannot read the state,\n"
|
<<?Pos(12, 5)
|
||||||
|
"The init function should return the initial state as its result and cannot read the state,\n"
|
||||||
"but it calls\n"
|
"but it calls\n"
|
||||||
" - new_state (at line 12, column 5), which calls\n"
|
" - new_state (at line 12, column 5), which calls\n"
|
||||||
" - state (at line 5, column 29)">>,
|
" - state (at line 5, column 29)">>,
|
||||||
<<"The init function should return the initial state as its result and cannot read the state,\n"
|
<<?Pos(13, 13)
|
||||||
|
"The init function should return the initial state as its result and cannot read the state,\n"
|
||||||
"but it calls\n"
|
"but it calls\n"
|
||||||
" - state (at line 13, column 13)">>]}
|
" - state (at line 13, column 13)">>]}
|
||||||
, {"field_parse_error",
|
, {"field_parse_error",
|
||||||
[<<"Cannot use nested fields or keys in record construction: p.x">>]}
|
[<<?Pos("field_parse_error", 5, 26)
|
||||||
|
"Cannot use nested fields or keys in record construction: p.x">>]}
|
||||||
, {"modifier_checks",
|
, {"modifier_checks",
|
||||||
[<<"The function all_the_things (at line 11, column 3) cannot be both public and private.">>,
|
[<<?Pos(11, 3)
|
||||||
<<"Namespaces cannot contain entrypoints (at line 3, column 3). Use 'function' instead.">>,
|
"The function all_the_things (at line 11, column 3) cannot be both public and private.">>,
|
||||||
<<"The contract Remote (at line 5, column 10) has no entrypoints. Since Sophia version 3.2, public\ncontract functions must be declared with the 'entrypoint' keyword instead of\n'function'.">>,
|
<<?Pos(3, 3)
|
||||||
<<"The entrypoint wha (at line 12, column 3) cannot be private. Use 'function' instead.">>,
|
"Namespaces cannot contain entrypoints (at line 3, column 3). Use 'function' instead.">>,
|
||||||
<<"Use 'entrypoint' for declaration of foo (at line 6, column 3):\n entrypoint foo : () => unit">>,
|
<<?Pos(5, 10)
|
||||||
<<"Use 'entrypoint' instead of 'function' for public function foo (at line 10, column 3):\n entrypoint foo() = ()">>,
|
"The contract Remote (at line 5, column 10) has no entrypoints. Since Sophia version 3.2, public\ncontract functions must be declared with the 'entrypoint' keyword instead of\n'function'.">>,
|
||||||
<<"Use 'entrypoint' instead of 'function' for public function foo (at line 6, column 3):\n entrypoint foo : () => unit">>]}
|
<<?Pos(12, 3)
|
||||||
|
"The entrypoint wha (at line 12, column 3) cannot be private. Use 'function' instead.">>,
|
||||||
|
<<?Pos(6, 3)
|
||||||
|
"Use 'entrypoint' for declaration of foo (at line 6, column 3):\n entrypoint foo : () => unit">>,
|
||||||
|
<<?Pos(10, 3)
|
||||||
|
"Use 'entrypoint' instead of 'function' for public function foo (at line 10, column 3):\n entrypoint foo() = ()">>,
|
||||||
|
<<?Pos(6, 3)
|
||||||
|
"Use 'entrypoint' instead of 'function' for public function foo (at line 6, column 3):\n entrypoint foo : () => unit">>]}
|
||||||
, {"list_comp_not_a_list",
|
, {"list_comp_not_a_list",
|
||||||
[<<"Cannot unify int\n and list('a)\nwhen checking rvalue of list comprehension binding at line 2, column 36\n 1 : int\nagainst type \n list('a)">>
|
[<<?Pos(2, 36)
|
||||||
|
"Cannot unify int\n and list('a)\nwhen checking rvalue of list comprehension binding at line 2, column 36\n 1 : int\nagainst type \n list('a)">>
|
||||||
]}
|
]}
|
||||||
, {"list_comp_if_not_bool",
|
, {"list_comp_if_not_bool",
|
||||||
[<<"Cannot unify int\n and bool\nwhen checking the type of the expression at line 2, column 44\n 3 : int\nagainst the expected type\n bool">>
|
[<<?Pos(2, 44)
|
||||||
|
"Cannot unify int\n and bool\nwhen checking the type of the expression at line 2, column 44\n 3 : int\nagainst the expected type\n bool">>
|
||||||
]}
|
]}
|
||||||
, {"list_comp_bad_shadow",
|
, {"list_comp_bad_shadow",
|
||||||
[<<"Cannot unify int\n and string\nwhen checking the type of the pattern at line 2, column 53\n x : int\nagainst the expected type\n string">>
|
[<<?Pos(2, 53)
|
||||||
|
"Cannot unify int\n and string\nwhen checking the type of the pattern at line 2, column 53\n x : int\nagainst the expected type\n string">>
|
||||||
]}
|
]}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
-define(Path(File), "code_errors/" ??File).
|
||||||
|
-define(Msg(File, Line, Col, Err), <<?Pos(?Path(File), Line, Col) Err>>).
|
||||||
|
|
||||||
|
-define(SAME(File, Line, Col, Err), {?Path(File), ?Msg(File, Line, Col, Err)}).
|
||||||
|
-define(AEVM(File, Line, Col, Err), {?Path(File), [{aevm, ?Msg(File, Line, Col, Err)}]}).
|
||||||
|
-define(FATE(File, Line, Col, Err), {?Path(File), [{fate, ?Msg(File, Line, Col, Err)}]}).
|
||||||
|
-define(BOTH(File, Line, Col, ErrAEVM, ErrFATE),
|
||||||
|
{?Path(File), [{aevm, ?Msg(File, Line, Col, ErrAEVM)},
|
||||||
|
{fate, ?Msg(File, Line, Col, ErrFATE)}]}).
|
||||||
|
|
||||||
|
failing_code_gen_contracts() ->
|
||||||
|
[ ?SAME(last_declaration_must_be_contract, 1, 1,
|
||||||
|
"Expected a contract as the last declaration instead of the namespace 'LastDeclarationIsNotAContract'")
|
||||||
|
, ?AEVM(polymorphic_entrypoint, 2, 17,
|
||||||
|
"The argument\n"
|
||||||
|
" x : 'a\n"
|
||||||
|
"of entrypoint 'id' does not have a monomorphic type.\n"
|
||||||
|
"Use the FATE backend if you want polymorphic entrypoints.")
|
||||||
|
, ?SAME(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'.")
|
||||||
|
, ?SAME(parameterised_state, 3, 8,
|
||||||
|
"The state type cannot be parameterized.")
|
||||||
|
, ?SAME(parameterised_event, 3, 12,
|
||||||
|
"The event type cannot be parameterized.")
|
||||||
|
, ?SAME(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).")
|
||||||
|
, ?SAME(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).")
|
||||||
|
, ?AEVM(polymorphic_compare, 4, 5,
|
||||||
|
"Cannot compare values of type\n"
|
||||||
|
" 'a\n"
|
||||||
|
"The AEVM only supports '==' on values of\n"
|
||||||
|
"- word type (int, bool, bits, address, oracle(_, _), etc)\n"
|
||||||
|
"- type string\n"
|
||||||
|
"- tuple or record of word type\n"
|
||||||
|
"Use FATE if you need to compare arbitrary types.")
|
||||||
|
, ?AEVM(higher_order_compare, 4, 5,
|
||||||
|
"Cannot compare values of type\n"
|
||||||
|
" (int) => int\n"
|
||||||
|
"The AEVM only supports '<' on values of\n"
|
||||||
|
"- word type (int, bool, bits, address, oracle(_, _), etc)\n"
|
||||||
|
"Use FATE if you need to compare arbitrary types.")
|
||||||
|
].
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ simple_contracts_test_() ->
|
|||||||
RightAssoc = fun(Op) -> CheckParens({a, Op, {b, Op, c}}) end,
|
RightAssoc = fun(Op) -> CheckParens({a, Op, {b, Op, c}}) end,
|
||||||
NonAssoc = fun(Op) ->
|
NonAssoc = fun(Op) ->
|
||||||
OpAtom = list_to_atom(Op),
|
OpAtom = list_to_atom(Op),
|
||||||
?assertThrow({parse_errors, [_]},
|
?assertThrow({error, [_]},
|
||||||
parse_expr(NoPar({a, Op, {b, Op, c}}))) end,
|
parse_expr(NoPar({a, Op, {b, Op, c}}))) end,
|
||||||
Stronger = fun(Op1, Op2) ->
|
Stronger = fun(Op1, Op2) ->
|
||||||
CheckParens({{a, Op1, b}, Op2, c}),
|
CheckParens({{a, Op1, b}, Op2, c}),
|
||||||
|
9
test/contracts/code_errors/bad_aens_resolve.aes
Normal file
9
test/contracts/code_errors/bad_aens_resolve.aes
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
contract BadAENSresolve =
|
||||||
|
|
||||||
|
type t('a) = option(list('a))
|
||||||
|
|
||||||
|
function fail() : t(int) =
|
||||||
|
AENS.resolve("foo.aet", "whatever")
|
||||||
|
|
||||||
|
entrypoint main() = ()
|
||||||
|
|
8
test/contracts/code_errors/higher_order_compare.aes
Normal file
8
test/contracts/code_errors/higher_order_compare.aes
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
contract HigherOrderCompare =
|
||||||
|
|
||||||
|
function cmp(x : int => int, y) : bool =
|
||||||
|
x < y
|
||||||
|
|
||||||
|
entrypoint test() =
|
||||||
|
let f(x) = (y) => x + y
|
||||||
|
cmp(f(1), f(2))
|
@ -0,0 +1,2 @@
|
|||||||
|
namespace LastDeclarationIsNotAContract =
|
||||||
|
function add(x, y) = x + y
|
3
test/contracts/code_errors/missing_init_function.aes
Normal file
3
test/contracts/code_errors/missing_init_function.aes
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
contract MissingInitFunction =
|
||||||
|
type state = int * int
|
||||||
|
|
4
test/contracts/code_errors/parameterised_event.aes
Normal file
4
test/contracts/code_errors/parameterised_event.aes
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
contract ParameterisedEvent =
|
||||||
|
|
||||||
|
datatype event('a) = Event(int)
|
||||||
|
|
4
test/contracts/code_errors/parameterised_state.aes
Normal file
4
test/contracts/code_errors/parameterised_state.aes
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
contract ParameterisedState =
|
||||||
|
|
||||||
|
type state('a) = list('a)
|
||||||
|
|
7
test/contracts/code_errors/polymorphic_aens_resolve.aes
Normal file
7
test/contracts/code_errors/polymorphic_aens_resolve.aes
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
contract PolymorphicAENSresolve =
|
||||||
|
|
||||||
|
function fail() : option('a) =
|
||||||
|
AENS.resolve("foo.aet", "whatever")
|
||||||
|
|
||||||
|
entrypoint main() = ()
|
||||||
|
|
7
test/contracts/code_errors/polymorphic_compare.aes
Normal file
7
test/contracts/code_errors/polymorphic_compare.aes
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
contract PolymorphicCompare =
|
||||||
|
|
||||||
|
function cmp(x : 'a, y : 'a) : bool =
|
||||||
|
x == y
|
||||||
|
|
||||||
|
entrypoint test() =
|
||||||
|
cmp(4, 6) && cmp(true, false)
|
3
test/contracts/code_errors/polymorphic_entrypoint.aes
Normal file
3
test/contracts/code_errors/polymorphic_entrypoint.aes
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
contract PolymorphicEntrypoint =
|
||||||
|
entrypoint id(x : 'a) : 'a = x
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user