Check that there are no maps in map keys already in type checker
This commit is contained in:
parent
510935d945
commit
0533ab27e1
@ -1708,7 +1708,7 @@ solve_known_record_types(Env, Constraints) ->
|
|||||||
C
|
C
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
type_error({not_a_record_type, RecId, When}),
|
type_error({not_a_record_type, RecType, When}),
|
||||||
not_solved
|
not_solved
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1823,6 +1823,10 @@ unfold_types(_Env, X, _Options) ->
|
|||||||
unfold_types_in_type(Env, T) ->
|
unfold_types_in_type(Env, T) ->
|
||||||
unfold_types_in_type(Env, T, []).
|
unfold_types_in_type(Env, T, []).
|
||||||
|
|
||||||
|
unfold_types_in_type(Env, {app_t, Ann, Id = {id, _, "map"}, Args = [KeyType0, _]}, Options) ->
|
||||||
|
Args1 = [KeyType, _] = unfold_types_in_type(Env, Args, Options),
|
||||||
|
[ type_error({map_in_map_key, KeyType0}) || has_maps(KeyType) ],
|
||||||
|
{app_t, Ann, Id, Args1};
|
||||||
unfold_types_in_type(Env, {app_t, Ann, Id, Args}, Options) when ?is_type_id(Id) ->
|
unfold_types_in_type(Env, {app_t, Ann, Id, Args}, Options) when ?is_type_id(Id) ->
|
||||||
UnfoldRecords = proplists:get_value(unfold_record_types, Options, false),
|
UnfoldRecords = proplists:get_value(unfold_record_types, Options, false),
|
||||||
UnfoldVariants = proplists:get_value(unfold_variant_types, Options, false),
|
UnfoldVariants = proplists:get_value(unfold_variant_types, Options, false),
|
||||||
@ -1870,6 +1874,13 @@ unfold_types_in_type(Env, [H|T], Options) ->
|
|||||||
unfold_types_in_type(_Env, X, _Options) ->
|
unfold_types_in_type(_Env, X, _Options) ->
|
||||||
X.
|
X.
|
||||||
|
|
||||||
|
has_maps({app_t, _, {id, _, "map"}, _}) ->
|
||||||
|
true;
|
||||||
|
has_maps(L) when is_list(L) ->
|
||||||
|
lists:any(fun has_maps/1, L);
|
||||||
|
has_maps(T) when is_tuple(T) ->
|
||||||
|
has_maps(tuple_to_list(T));
|
||||||
|
has_maps(_) -> false.
|
||||||
|
|
||||||
subst_tvars(Env, Type) ->
|
subst_tvars(Env, Type) ->
|
||||||
subst_tvars1([{V, T} || {{tvar, _, V}, T} <- Env], Type).
|
subst_tvars1([{V, T} || {{tvar, _, V}, T} <- Env], Type).
|
||||||
@ -2282,6 +2293,10 @@ mk_error({new_tuple_syntax, Ann, Ts}) ->
|
|||||||
Msg = io_lib:format("Invalid type\n~s (at ~s)\nThe syntax of tuple types changed in Sophia version 4.0. Did you mean\n~s\n",
|
Msg = io_lib:format("Invalid type\n~s (at ~s)\nThe syntax of tuple types changed in Sophia version 4.0. Did you mean\n~s\n",
|
||||||
[pp_type(" ", {args_t, Ann, Ts}), pp_loc(Ann), pp_type(" ", {tuple_t, Ann, Ts})]),
|
[pp_type(" ", {args_t, Ann, Ts}), pp_loc(Ann), pp_type(" ", {tuple_t, Ann, Ts})]),
|
||||||
mk_t_err(pos(Ann), Msg);
|
mk_t_err(pos(Ann), Msg);
|
||||||
|
mk_error({map_in_map_key, KeyType}) ->
|
||||||
|
Msg = io_lib:format("Invalid key type\n~s\n", [pp_type(" ", KeyType)]),
|
||||||
|
Cxt = "Map keys cannot contain other maps.\n",
|
||||||
|
mk_t_err(pos(KeyType), Msg, Cxt);
|
||||||
mk_error(Err) ->
|
mk_error(Err) ->
|
||||||
Msg = io_lib:format("Unknown error: ~p\n", [Err]),
|
Msg = io_lib:format("Unknown error: ~p\n", [Err]),
|
||||||
mk_t_err(pos(0, 0), Msg).
|
mk_t_err(pos(0, 0), Msg).
|
||||||
|
@ -718,15 +718,11 @@ eta_expand(Id = {_, Ann0, _}, {fun_t, _, _, ArgsT, _}, Icode) ->
|
|||||||
check_monomorphic_map({typed, Ann, _, MapType}, Icode) ->
|
check_monomorphic_map({typed, Ann, _, MapType}, Icode) ->
|
||||||
check_monomorphic_map(Ann, MapType, Icode).
|
check_monomorphic_map(Ann, MapType, Icode).
|
||||||
|
|
||||||
check_monomorphic_map(Ann, Type = ?map_t(KeyType, ValType), Icode) ->
|
check_monomorphic_map(Ann, ?map_t(KeyType, ValType), _Icode) ->
|
||||||
case is_monomorphic(KeyType) of
|
Err = fun(Why) -> gen_error({invalid_map_key_type, Why, Ann, KeyType}) end,
|
||||||
true ->
|
[ Err(polymorphic) || not is_monomorphic(KeyType) ],
|
||||||
case has_maps(ast_type(KeyType, Icode)) of
|
[ Err(function) || not is_first_order_type(KeyType) ],
|
||||||
false -> {KeyType, ValType};
|
{KeyType, ValType}.
|
||||||
true -> gen_error({cant_use_map_as_map_keys, Ann, Type})
|
|
||||||
end;
|
|
||||||
false -> gen_error({cant_compile_map_with_polymorphic_keys, Ann, Type})
|
|
||||||
end.
|
|
||||||
|
|
||||||
map_empty(KeyType, ValType, Icode) ->
|
map_empty(KeyType, ValType, Icode) ->
|
||||||
prim_call(?PRIM_CALL_MAP_EMPTY, #integer{value = 0},
|
prim_call(?PRIM_CALL_MAP_EMPTY, #integer{value = 0},
|
||||||
@ -928,14 +924,6 @@ ast_fun_to_icode(Name, Attrs, Args, Body, TypeRep, #{functions := Funs} = Icode)
|
|||||||
NewFuns = [{Name, Attrs, Args, Body, TypeRep}| Funs],
|
NewFuns = [{Name, Attrs, Args, Body, TypeRep}| Funs],
|
||||||
aeso_icode:set_functions(NewFuns, Icode).
|
aeso_icode:set_functions(NewFuns, Icode).
|
||||||
|
|
||||||
has_maps({map, _, _}) -> true;
|
|
||||||
has_maps(word) -> false;
|
|
||||||
has_maps(string) -> false;
|
|
||||||
has_maps(typerep) -> false;
|
|
||||||
has_maps({list, T}) -> has_maps(T);
|
|
||||||
has_maps({tuple, Ts}) -> lists:any(fun has_maps/1, Ts);
|
|
||||||
has_maps({variant, Cs}) -> lists:any(fun has_maps/1, lists:append(Cs)).
|
|
||||||
|
|
||||||
%% A function is private if not an 'entrypoint', or if it's not defined in the
|
%% A function is private if not an 'entrypoint', or if it's not defined in the
|
||||||
%% main contract name space. (NOTE: changes when we introduce inheritance).
|
%% main contract name space. (NOTE: changes when we introduce inheritance).
|
||||||
is_private(Ann, #{ contract_name := MainContract } = Icode) ->
|
is_private(Ann, #{ contract_name := MainContract } = Icode) ->
|
||||||
|
@ -468,6 +468,15 @@ failing_contracts() ->
|
|||||||
[<<?Pos(2, 53)
|
[<<?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">>
|
"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">>
|
||||||
]}
|
]}
|
||||||
|
, {"map_as_map_key",
|
||||||
|
[<<?Pos(5, 25)
|
||||||
|
"Invalid key type\n"
|
||||||
|
" map(int, int)\n"
|
||||||
|
"Map keys cannot contain other maps.">>,
|
||||||
|
<<?Pos(6, 25)
|
||||||
|
"Invalid key type\n"
|
||||||
|
" lm\n"
|
||||||
|
"Map keys cannot contain other maps.">>]}
|
||||||
].
|
].
|
||||||
|
|
||||||
-define(Path(File), "code_errors/" ??File).
|
-define(Path(File), "code_errors/" ??File).
|
||||||
|
6
test/contracts/map_as_map_key.aes
Normal file
6
test/contracts/map_as_map_key.aes
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
contract MapAsMapKey =
|
||||||
|
type t('key) = map('key, int)
|
||||||
|
type lm = list(map(int, int))
|
||||||
|
|
||||||
|
entrypoint foo(m) : t(map(int, int)) = {[m] = 0}
|
||||||
|
entrypoint bar(m) : t(lm) = Map.delete(m, {})
|
Loading…
x
Reference in New Issue
Block a user