diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index 8aa0433..3ae5534 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -132,6 +132,7 @@ , namespace = [] :: qname() , used_namespaces = [] :: used_namespaces() , in_pattern = false :: boolean() + , in_guard = false :: boolean() , stateful = false :: boolean() , current_function = none :: none | aeso_syntax:id() , what = top :: top | namespace | contract | contract_interface @@ -1396,7 +1397,7 @@ infer_letfun1(Env0, {letfun, Attrib, Fun = {id, NameAttrib, Name}, Args, What, G Env = Env0#env{ stateful = aeso_syntax:get_ann(stateful, Attrib, false), current_function = Fun }, {NewEnv, {typed, _, {tuple, _, TypedArgs}, {tuple_t, _, ArgTypes}}} = infer_pattern(Env, {tuple, [{origin, system} | NameAttrib], Args}), - NewGuard = check_expr(NewEnv#env{ stateful = false }, Guard, {id, Attrib, "bool"}), + NewGuard = check_expr(NewEnv#env{ in_guard = true }, Guard, {id, Attrib, "bool"}), ExpectedType = check_type(Env, arg_type(NameAttrib, What)), NewBody={typed, _, _, ResultType} = check_expr(NewEnv, Body, ExpectedType), NamedArgs = [], @@ -1465,6 +1466,12 @@ lookup_name(Env, As, Id, Options) -> {set_qname(QId, Id), Ty1} end. +check_stateful(#env{ in_guard = true }, Id, Type = {type_sig, _, _, _, _, _}) -> + case aeso_syntax:get_ann(stateful, Type, false) of + false -> ok; + true -> + type_error({stateful_not_allowed_in_guards, Id}) + end; check_stateful(#env{ stateful = false, current_function = Fun }, Id, Type = {type_sig, _, _, _, _, _}) -> case aeso_syntax:get_ann(stateful, Type, false) of false -> ok; @@ -1913,7 +1920,7 @@ infer_case(Env, Attrs, Pattern, Guard, ExprType, Branch, SwitchType) -> none -> {'case', Attrs, NewPattern, NewBranch}; _ -> - NewGuard = check_expr(NewEnv#env{ stateful = false }, Guard, {id, Attrs, "bool"}), + NewGuard = check_expr(NewEnv#env{ in_guard = true }, Guard, {id, Attrs, "bool"}), {'case', Attrs, NewPattern, NewGuard, NewBranch} end. @@ -3008,6 +3015,10 @@ mk_error({stateful_not_allowed, Id, Fun}) -> Msg = io_lib:format("Cannot reference stateful function ~s (at ~s)\nin the definition of non-stateful function ~s.\n", [pp(Id), pp_loc(Id), pp(Fun)]), mk_t_err(pos(Id), Msg); +mk_error({stateful_not_allowed_in_guards, Id}) -> + Msg = io_lib:format("Cannot reference stateful function ~s (at ~s) in a pattern guard.\n", + [pp(Id), pp_loc(Id)]), + mk_t_err(pos(Id), Msg); mk_error({value_arg_not_allowed, Value, Fun}) -> Msg = io_lib:format("Cannot pass non-zero value argument ~s (at ~s)\nin the definition of non-stateful function ~s.\n", [pp_expr("", Value), pp_loc(Value), pp(Fun)]), diff --git a/test/aeso_compiler_tests.erl b/test/aeso_compiler_tests.erl index af88614..8ad091b 100644 --- a/test/aeso_compiler_tests.erl +++ b/test/aeso_compiler_tests.erl @@ -809,6 +809,10 @@ failing_contracts() -> [<> ]) + , ?TYPE_ERROR(stateful_pattern_guard, + [<> + ]) ]. -define(Path(File), "code_errors/" ??File). diff --git a/test/contracts/stateful_pattern_guard.aes b/test/contracts/stateful_pattern_guard.aes new file mode 100644 index 0000000..e3706b4 --- /dev/null +++ b/test/contracts/stateful_pattern_guard.aes @@ -0,0 +1,12 @@ +include "List.aes" + +contract C = + type state = int + + entrypoint init() = f(4) + + function + f(x) | x > 0 = 1 + f(x) | g(x) = 2 + + stateful function g(x) = x < 0