Add using namespace parts to ast type inference
This commit is contained in:
parent
81e4429585
commit
c29e9a7b2e
@ -103,6 +103,8 @@
|
||||
-type typesig() :: {type_sig, aeso_syntax:ann(), type_constraints(), [aeso_syntax:named_arg_t()], [type()], type()}.
|
||||
|
||||
-type namespace_alias() :: none | name().
|
||||
-type namespace_parts() :: none | {for, [name()]} | {hiding, [name()]}.
|
||||
-type used_namespaces() :: [{qname(), namespace_alias(), namespace_parts()}].
|
||||
|
||||
-type type_constraints() :: none | bytes_concat | bytes_split | address_to_contract | bytecode_hash.
|
||||
|
||||
@ -128,7 +130,7 @@
|
||||
, typevars = unrestricted :: unrestricted | [name()]
|
||||
, fields = #{} :: #{ name() => [field_info()] } %% fields are global
|
||||
, namespace = [] :: qname()
|
||||
, used_namespaces = [] :: [{qname(), namespace_alias()}]
|
||||
, used_namespaces = [] :: used_namespaces()
|
||||
, in_pattern = false :: boolean()
|
||||
, stateful = false :: boolean()
|
||||
, current_function = none :: none | aeso_syntax:id()
|
||||
@ -324,8 +326,39 @@ possible_scopes(#env{ namespace = Current, used_namespaces = UsedNamespaces }, N
|
||||
lists:map(fun(X) -> element(1, X) end, Namespaces)
|
||||
end,
|
||||
Ret1 = [ lists:sublist(Current, I) ++ Q || I <- lists:seq(0, length(Current)), Q <- NewQuals ],
|
||||
Ret2 = [ Namespace ++ Q || {Namespace, none} <- UsedNamespaces, Q <- NewQuals ],
|
||||
Ret1 ++ Ret2.
|
||||
Ret2 = [ Namespace ++ Q || {Namespace, none, _} <- UsedNamespaces, Q <- NewQuals ],
|
||||
lists:usort(Ret1 ++ Ret2).
|
||||
|
||||
-spec visible_in_used_namespaces(used_namespaces(), qname()) -> boolean().
|
||||
visible_in_used_namespaces(UsedNamespaces, QName) ->
|
||||
Qual = lists:droplast(QName),
|
||||
Name = lists:last(QName),
|
||||
case lists:filter(fun({Ns, _, _}) -> Qual == Ns end, UsedNamespaces) of
|
||||
[] ->
|
||||
true;
|
||||
Namespaces ->
|
||||
IsVisible = fun(Namespace) ->
|
||||
case Namespace of
|
||||
{_, _, {for, Names}} ->
|
||||
case lists:member(Name, Names) of
|
||||
true ->
|
||||
true;
|
||||
false ->
|
||||
false
|
||||
end;
|
||||
{_, _, {hiding, Names}} ->
|
||||
case lists:member(Name, Names) of
|
||||
true ->
|
||||
false;
|
||||
false ->
|
||||
true
|
||||
end;
|
||||
_ ->
|
||||
true
|
||||
end
|
||||
end,
|
||||
lists:any(IsVisible, Namespaces)
|
||||
end.
|
||||
|
||||
-spec lookup_type(env(), type_id()) -> false | {qname(), type_info()}.
|
||||
lookup_type(Env, Id) ->
|
||||
@ -352,7 +385,7 @@ lookup_env(Env, Kind, Ann, Name) ->
|
||||
end.
|
||||
|
||||
-spec lookup_env1(env(), type | term, aeso_syntax:ann(), qname()) -> false | {qname(), fun_info()}.
|
||||
lookup_env1(#env{ namespace = Current, scopes = Scopes }, Kind, Ann, QName) ->
|
||||
lookup_env1(#env{ namespace = Current, used_namespaces = UsedNamespaces, scopes = Scopes }, Kind, Ann, QName) ->
|
||||
Qual = lists:droplast(QName),
|
||||
Name = lists:last(QName),
|
||||
AllowPrivate = lists:prefix(Qual, Current),
|
||||
@ -376,7 +409,11 @@ lookup_env1(#env{ namespace = Current, scopes = Scopes }, Kind, Ann, QName) ->
|
||||
{Ann1, _} = E ->
|
||||
%% Check that it's not private (or we can see private funs)
|
||||
case not is_private(Ann1) orelse AllowPrivate of
|
||||
true -> {QName, E};
|
||||
true ->
|
||||
case visible_in_used_namespaces(UsedNamespaces, QName) of
|
||||
true -> {QName, E};
|
||||
false -> false
|
||||
end;
|
||||
false -> false
|
||||
end
|
||||
end
|
||||
@ -814,7 +851,7 @@ infer1(Env, [{namespace, Ann, Name, Code} | Rest], Acc, Options) ->
|
||||
{Env1, Code1} = infer_contract_top(push_scope(namespace, Name, Env), namespace, Code, Options),
|
||||
Namespace1 = {namespace, Ann, Name, Code1},
|
||||
infer1(pop_scope(Env1), Rest, [Namespace1 | Acc], Options);
|
||||
infer1(Env, [Using = {using, _, _, _} | Rest], Acc, Options) ->
|
||||
infer1(Env, [Using = {using, _, _, _, _} | Rest], Acc, Options) ->
|
||||
infer1(check_usings(Env, Using), Rest, Acc, Options);
|
||||
infer1(Env, [{pragma, _, _} | Rest], Acc, Options) ->
|
||||
%% Pragmas are checked in check_modifiers
|
||||
@ -872,7 +909,7 @@ infer_contract(Env0, What, Defs0, Options) ->
|
||||
({letfun, _, _, _, _, _}) -> function;
|
||||
({fun_clauses, _, _, _, _}) -> function;
|
||||
({fun_decl, _, _, _}) -> prototype;
|
||||
({using, _, _, _}) -> using;
|
||||
({using, _, _, _, _}) -> using;
|
||||
(_) -> unexpected
|
||||
end,
|
||||
Get = fun(K, In) -> [ Def || Def <- In, Kind(Def) == K ] end,
|
||||
@ -1008,7 +1045,7 @@ check_typedef(Env, {variant_t, Cons}) ->
|
||||
|
||||
check_usings(Env, []) ->
|
||||
Env;
|
||||
check_usings(Env = #env{ used_namespaces = UsedNamespaces }, [{using, Ann, Con, Alias} | Rest]) ->
|
||||
check_usings(Env = #env{ used_namespaces = UsedNamespaces }, [{using, Ann, Con, Alias, Parts} | Rest]) ->
|
||||
AliasName = case Alias of
|
||||
none ->
|
||||
none;
|
||||
@ -1020,10 +1057,27 @@ check_usings(Env = #env{ used_namespaces = UsedNamespaces }, [{using, Ann, Con,
|
||||
create_type_errors(),
|
||||
type_error({using_undefined_namespace, Ann, qname(Con)}),
|
||||
destroy_and_report_type_errors(Env);
|
||||
_ ->
|
||||
check_usings(Env#env{ used_namespaces = UsedNamespaces ++ [{qname(Con), AliasName}] }, Rest)
|
||||
Scope ->
|
||||
Nsp = case Parts of
|
||||
none ->
|
||||
{qname(Con), AliasName, none};
|
||||
{ForOrHiding, Ids} ->
|
||||
IsUndefined = fun(Id) ->
|
||||
proplists:lookup(name(Id), Scope#scope.funs) == none
|
||||
end,
|
||||
UndefinedIds = lists:filter(IsUndefined, Ids),
|
||||
case UndefinedIds of
|
||||
[] ->
|
||||
{qname(Con), AliasName, {ForOrHiding, lists:map(fun name/1, Ids)}};
|
||||
_ ->
|
||||
create_type_errors(),
|
||||
type_error({using_undefined_namespace_parts, Ann, qname(Con), lists:map(fun qname/1, UndefinedIds)}),
|
||||
destroy_and_report_type_errors(Env)
|
||||
end
|
||||
end,
|
||||
check_usings(Env#env{ used_namespaces = UsedNamespaces ++ [Nsp] }, Rest)
|
||||
end;
|
||||
check_usings(Env, Using = {using, _, _, _}) ->
|
||||
check_usings(Env, Using = {using, _, _, _, _}) ->
|
||||
check_usings(Env, [Using]).
|
||||
|
||||
check_unexpected(Xs) ->
|
||||
@ -1055,7 +1109,7 @@ check_modifiers_(Env, [{namespace, _, _, Decls} | Rest]) ->
|
||||
check_modifiers_(Env, [{pragma, Ann, Pragma} | Rest]) ->
|
||||
check_pragma(Env, Ann, Pragma),
|
||||
check_modifiers_(Env, Rest);
|
||||
check_modifiers_(Env, [{using, _, _, _} | Rest]) ->
|
||||
check_modifiers_(Env, [{using, _, _, _, _} | Rest]) ->
|
||||
check_modifiers_(Env, Rest);
|
||||
check_modifiers_(Env, [Decl | Rest]) ->
|
||||
type_error({bad_top_level_decl, Decl}),
|
||||
@ -1810,7 +1864,7 @@ infer_block(Env, _, [{letval, Attrs, Pattern, E}|Rest], BlockType) ->
|
||||
{'case', _, NewPattern, {typed, _, {block, _, NewRest}, _}} =
|
||||
infer_case(Env, Attrs, Pattern, PatType, {block, Attrs, Rest}, BlockType),
|
||||
[{letval, Attrs, NewPattern, NewE}|NewRest];
|
||||
infer_block(Env, Attrs, [Using = {using, _, _, _} | Rest], BlockType) ->
|
||||
infer_block(Env, Attrs, [Using = {using, _, _, _, _} | Rest], BlockType) ->
|
||||
infer_block(check_usings(Env, Using), Attrs, Rest, BlockType);
|
||||
infer_block(Env, Attrs, [E|Rest], BlockType) ->
|
||||
[infer_expr(Env, E)|infer_block(Env, Attrs, Rest, BlockType)].
|
||||
@ -3036,6 +3090,10 @@ mk_error({ambiguous_name, QIds = [{qid, Ann, _} | _]}) ->
|
||||
mk_error({using_undefined_namespace, Ann, Namespace}) ->
|
||||
Msg = io_lib:format("Cannot use undefined namespace ~s", [Namespace]),
|
||||
mk_t_err(pos(Ann), Msg);
|
||||
mk_error({using_undefined_namespace_parts, Ann, Namespace, Parts}) ->
|
||||
PartsStr = lists:concat(lists:join(", ", Parts)),
|
||||
Msg = io_lib:format("The namespace ~s does not define the following names: ~s", [Namespace, PartsStr]),
|
||||
mk_t_err(pos(Ann), Msg);
|
||||
mk_error(Err) ->
|
||||
Msg = io_lib:format("Unknown error: ~p\n", [Err]),
|
||||
mk_t_err(pos(0, 0), Msg).
|
||||
|
Loading…
x
Reference in New Issue
Block a user