Move invalid_oracle_type error to type checker
This commit is contained in:
parent
f22c1aa82e
commit
eb77ae4137
@ -88,8 +88,10 @@
|
|||||||
| {add_bytes, aeso_syntax:ann(), concat | split, utype(), utype(), utype()}.
|
| {add_bytes, aeso_syntax:ann(), concat | split, utype(), utype(), utype()}.
|
||||||
|
|
||||||
-type aens_resolve_constraint() :: {aens_resolve_type, utype()}.
|
-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().
|
-type constraint() :: named_argument_constraint() | field_constraint() | byte_constraint()
|
||||||
|
| aens_resolve_constraint() | oracle_type_constraint().
|
||||||
|
|
||||||
-record(field_info,
|
-record(field_info,
|
||||||
{ ann :: aeso_syntax:ann()
|
{ ann :: aeso_syntax:ann()
|
||||||
@ -1648,6 +1650,14 @@ 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(Tup) when is_tuple(Tup) -> is_first_order(tuple_to_list(Tup));
|
||||||
is_first_order(_) -> true.
|
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) ->
|
check_state_init(Env) ->
|
||||||
Top = Env#env.namespace,
|
Top = Env#env.namespace,
|
||||||
StateType = lookup_type(Env, {id, [{origin, system}], "state"}),
|
StateType = lookup_type(Env, {id, [{origin, system}], "state"}),
|
||||||
@ -1822,6 +1832,9 @@ infer_expr(Env, {app, Ann, Fun, Args0} = App) ->
|
|||||||
when_warning(warn_negative_spend, fun() -> warn_potential_negative_spend(Ann, NewFun1, NewArgs) end),
|
when_warning(warn_negative_spend, fun() -> warn_potential_negative_spend(Ann, NewFun1, NewArgs) end),
|
||||||
[ add_constraint({aens_resolve_type, GeneralResultType})
|
[ add_constraint({aens_resolve_type, GeneralResultType})
|
||||||
|| element(3, FunName) =:= ["AENS", "resolve"] ],
|
|| element(3, FunName) =:= ["AENS", "resolve"] ],
|
||||||
|
[ add_constraint({oracle_type, Ann, OType})
|
||||||
|
|| OType <- [get_oracle_type(FunName, ArgTypes, GeneralResultType)],
|
||||||
|
OType =/= false ],
|
||||||
add_constraint(
|
add_constraint(
|
||||||
#dependent_type_constraint{ named_args_t = NamedArgsVar,
|
#dependent_type_constraint{ named_args_t = NamedArgsVar,
|
||||||
named_args = NamedArgs1,
|
named_args = NamedArgs1,
|
||||||
@ -2347,10 +2360,14 @@ destroy_and_report_unsolved_constraints(Env) ->
|
|||||||
({add_bytes, _, _, _, _, _}) -> true;
|
({add_bytes, _, _, _, _, _}) -> true;
|
||||||
(_) -> false
|
(_) -> false
|
||||||
end, OtherCs3),
|
end, OtherCs3),
|
||||||
{AensResolveCs, []} =
|
{AensResolveCs, OtherCs5} =
|
||||||
lists:partition(fun({aens_resolve_type, _}) -> true;
|
lists:partition(fun({aens_resolve_type, _}) -> true;
|
||||||
(_) -> false
|
(_) -> false
|
||||||
end, OtherCs4),
|
end, OtherCs4),
|
||||||
|
{OracleTypeCs, []} =
|
||||||
|
lists:partition(fun({oracle_type, _, _}) -> true;
|
||||||
|
(_) -> false
|
||||||
|
end, OtherCs5),
|
||||||
|
|
||||||
Unsolved = [ S || S <- [ solve_constraint(Env, dereference_deep(C)) || C <- NamedArgCs ],
|
Unsolved = [ S || S <- [ solve_constraint(Env, dereference_deep(C)) || C <- NamedArgCs ],
|
||||||
S == unsolved ],
|
S == unsolved ],
|
||||||
@ -2369,9 +2386,19 @@ destroy_and_report_unsolved_constraints(Env) ->
|
|||||||
check_is_contract_constraints(Env, ContractCs),
|
check_is_contract_constraints(Env, ContractCs),
|
||||||
check_bytes_constraints(Env, BytesCs),
|
check_bytes_constraints(Env, BytesCs),
|
||||||
check_aens_resolve_constraints(Env, AensResolveCs),
|
check_aens_resolve_constraints(Env, AensResolveCs),
|
||||||
|
check_oracle_type_constraints(Env, OracleTypeCs),
|
||||||
|
|
||||||
destroy_constraints().
|
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 --
|
%% -- Named argument constraints --
|
||||||
|
|
||||||
%% If false, a type error has been emitted, so it's safe to drop the constraint.
|
%% If false, a type error has been emitted, so it's safe to drop the constraint.
|
||||||
@ -2513,6 +2540,17 @@ check_aens_resolve_constraints(Env, [{aens_resolve_type, Type} | Rest]) ->
|
|||||||
end,
|
end,
|
||||||
check_aens_resolve_constraints(Env, Rest).
|
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 --
|
%% -- Field constraints --
|
||||||
|
|
||||||
check_record_create_constraints(_, []) -> ok;
|
check_record_create_constraints(_, []) -> ok;
|
||||||
@ -3588,6 +3626,12 @@ mk_error({invalid_aens_resolve_type, Ann, T}) ->
|
|||||||
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)",
|
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)",
|
||||||
[pp_type(" `", T)]),
|
[pp_type(" `", T)]),
|
||||||
mk_t_err(pos(Ann), Msg);
|
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) ->
|
mk_error(Err) ->
|
||||||
Msg = io_lib:format("Unknown error: ~p", [Err]),
|
Msg = io_lib:format("Unknown error: ~p", [Err]),
|
||||||
mk_t_err(pos(0, 0), Msg).
|
mk_t_err(pos(0, 0), Msg).
|
||||||
|
@ -534,7 +534,7 @@ expr_to_fcode(_Env, _Type, {bytes, _, B}) -> {lit, {bytes, B}};
|
|||||||
|
|
||||||
%% Variables
|
%% Variables
|
||||||
expr_to_fcode(Env, _Type, {id, _, X}) -> resolve_var(Env, [X]);
|
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
|
case resolve_var(Env, X) of
|
||||||
{builtin_u, B, Ar} when B =:= oracle_query;
|
{builtin_u, B, Ar} when B =:= oracle_query;
|
||||||
B =:= oracle_get_question;
|
B =:= oracle_get_question;
|
||||||
@ -545,7 +545,6 @@ expr_to_fcode(Env, Type, {qid, Ann, X}) ->
|
|||||||
B =:= oracle_check_query ->
|
B =:= oracle_check_query ->
|
||||||
OType = get_oracle_type(B, Type),
|
OType = get_oracle_type(B, Type),
|
||||||
{oracle, QType, RType} = type_to_fcode(Env, OType),
|
{oracle, QType, RType} = type_to_fcode(Env, OType),
|
||||||
validate_oracle_type(Ann, OType, QType, RType),
|
|
||||||
TypeArgs = [{lit, {typerep, QType}}, {lit, {typerep, RType}}],
|
TypeArgs = [{lit, {typerep, QType}}, {lit, {typerep, RType}}],
|
||||||
{builtin_u, B, Ar, TypeArgs};
|
{builtin_u, B, Ar, TypeArgs};
|
||||||
{builtin_u, B = aens_resolve, Ar} ->
|
{builtin_u, B = aens_resolve, Ar} ->
|
||||||
@ -803,35 +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_check_query, {fun_t, _, _, [OType | _], _}) -> OType;
|
||||||
get_oracle_type(oracle_respond, {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.
|
|
||||||
|
|
||||||
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 --
|
%% -- Pattern matching --
|
||||||
|
|
||||||
-spec alts_to_fcode(env(), ftype(), var_name(), [aeso_syntax:alt()], aeso_syntax:expr()) -> fsplit().
|
-spec alts_to_fcode(env(), ftype(), var_name(), [aeso_syntax:alt()], aeso_syntax:expr()) -> fsplit().
|
||||||
|
@ -10,12 +10,6 @@
|
|||||||
|
|
||||||
-export([format/1, pos/1]).
|
-export([format/1, pos/1]).
|
||||||
|
|
||||||
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}) ->
|
format({var_args_not_set, Expr}) ->
|
||||||
mk_err( pos(Expr), "Could not deduce type of variable arguments list"
|
mk_err( pos(Expr), "Could not deduce type of variable arguments list"
|
||||||
, "When compiling " ++ pp_expr(Expr)
|
, "When compiling " ++ pp_expr(Expr)
|
||||||
@ -36,9 +30,6 @@ pp_expr(E) ->
|
|||||||
pp_expr(N, E) ->
|
pp_expr(N, E) ->
|
||||||
prettypr:format(prettypr:nest(N, aeso_pretty:expr(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) ->
|
mk_err(Pos, Msg) ->
|
||||||
aeso_errors:new(code_error, Pos, lists:flatten(Msg)).
|
aeso_errors:new(code_error, Pos, lists:flatten(Msg)).
|
||||||
|
|
||||||
|
@ -45,12 +45,6 @@ simple_compile_test_() ->
|
|||||||
check_errors(ExpectedErrors, Errors)
|
check_errors(ExpectedErrors, Errors)
|
||||||
end} ||
|
end} ||
|
||||||
{ContractName, ExpectedErrors} <- failing_contracts() ] ++
|
{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",
|
[ {"Testing include with explicit files",
|
||||||
fun() ->
|
fun() ->
|
||||||
FileSystem = maps:from_list(
|
FileSystem = maps:from_list(
|
||||||
@ -1076,30 +1070,34 @@ failing_contracts() ->
|
|||||||
" `list(int)`\n"
|
" `list(int)`\n"
|
||||||
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
|
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
|
||||||
])
|
])
|
||||||
].
|
, ?TYPE_ERROR(polymorphic_query_type,
|
||||||
|
[<<?Pos(3,5)
|
||||||
-define(Path(File), "code_errors/" ??File).
|
"Invalid oracle type\n"
|
||||||
-define(Msg(File, Line, Col, Err), <<?Pos("Code generation", ?Path(File), Line, Col) Err>>).
|
" `oracle('a, 'b)`\n"
|
||||||
|
"The query type must not be polymorphic (contain type variables)">>,
|
||||||
-define(FATE_ERR(File, Line, Col, Err), {?Path(File), ?Msg(File, Line, Col, Err)}).
|
<<?Pos(3,5)
|
||||||
|
"Invalid oracle type\n"
|
||||||
failing_code_gen_contracts() ->
|
" `oracle('a, 'b)`\n"
|
||||||
[ ?FATE_ERR(polymorphic_query_type, 3, 5,
|
"The response type must not be polymorphic (contain type variables)">>
|
||||||
"Invalid oracle type\n"
|
])
|
||||||
" oracle('a, 'b)\n"
|
, ?TYPE_ERROR(polymorphic_response_type,
|
||||||
"The query type must not be polymorphic (contain type variables).")
|
[<<?Pos(3,5)
|
||||||
, ?FATE_ERR(polymorphic_response_type, 3, 5,
|
"Invalid oracle type\n"
|
||||||
"Invalid oracle type\n"
|
" `oracle(string, 'r)`\n"
|
||||||
" oracle(string, 'r)\n"
|
"The response type must not be polymorphic (contain type variables)">>
|
||||||
"The response type must not be polymorphic (contain type variables).")
|
])
|
||||||
, ?FATE_ERR(higher_order_query_type, 3, 5,
|
, ?TYPE_ERROR(higher_order_query_type,
|
||||||
"Invalid oracle type\n"
|
[<<?Pos(3,5)
|
||||||
" oracle((int) => int, string)\n"
|
"Invalid oracle type\n"
|
||||||
"The query type must not be higher-order (contain function types).")
|
" `oracle((int) => int, string)`\n"
|
||||||
, ?FATE_ERR(higher_order_response_type, 3, 5,
|
"The query type must not be higher-order (contain function types)">>
|
||||||
"Invalid oracle type\n"
|
])
|
||||||
" oracle(string, (int) => int)\n"
|
, ?TYPE_ERROR(higher_order_response_type,
|
||||||
"The response type must not be higher-order (contain function types).")
|
[<<?Pos(3,5)
|
||||||
|
"Invalid oracle type\n"
|
||||||
|
" `oracle(string, (int) => int)`\n"
|
||||||
|
"The response type must not be higher-order (contain function types)">>
|
||||||
|
])
|
||||||
].
|
].
|
||||||
|
|
||||||
validation_test_() ->
|
validation_test_() ->
|
||||||
|
Loading…
x
Reference in New Issue
Block a user