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 typesig() :: {type_sig, aeso_syntax:ann(), type_constraints(), [aeso_syntax:named_arg_t()], [type()], type()}.
|
||||||
|
|
||||||
-type namespace_alias() :: none | name().
|
-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.
|
-type type_constraints() :: none | bytes_concat | bytes_split | address_to_contract | bytecode_hash.
|
||||||
|
|
||||||
@ -128,7 +130,7 @@
|
|||||||
, typevars = unrestricted :: unrestricted | [name()]
|
, typevars = unrestricted :: unrestricted | [name()]
|
||||||
, fields = #{} :: #{ name() => [field_info()] } %% fields are global
|
, fields = #{} :: #{ name() => [field_info()] } %% fields are global
|
||||||
, namespace = [] :: qname()
|
, namespace = [] :: qname()
|
||||||
, used_namespaces = [] :: [{qname(), namespace_alias()}]
|
, used_namespaces = [] :: used_namespaces()
|
||||||
, in_pattern = false :: boolean()
|
, in_pattern = false :: boolean()
|
||||||
, stateful = false :: boolean()
|
, stateful = false :: boolean()
|
||||||
, current_function = none :: none | aeso_syntax:id()
|
, 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)
|
lists:map(fun(X) -> element(1, X) end, Namespaces)
|
||||||
end,
|
end,
|
||||||
Ret1 = [ lists:sublist(Current, I) ++ Q || I <- lists:seq(0, length(Current)), Q <- NewQuals ],
|
Ret1 = [ lists:sublist(Current, I) ++ Q || I <- lists:seq(0, length(Current)), Q <- NewQuals ],
|
||||||
Ret2 = [ Namespace ++ Q || {Namespace, none} <- UsedNamespaces, Q <- NewQuals ],
|
Ret2 = [ Namespace ++ Q || {Namespace, none, _} <- UsedNamespaces, Q <- NewQuals ],
|
||||||
Ret1 ++ Ret2.
|
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()}.
|
-spec lookup_type(env(), type_id()) -> false | {qname(), type_info()}.
|
||||||
lookup_type(Env, Id) ->
|
lookup_type(Env, Id) ->
|
||||||
@ -352,7 +385,7 @@ lookup_env(Env, Kind, Ann, Name) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
-spec lookup_env1(env(), type | term, aeso_syntax:ann(), qname()) -> false | {qname(), fun_info()}.
|
-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),
|
Qual = lists:droplast(QName),
|
||||||
Name = lists:last(QName),
|
Name = lists:last(QName),
|
||||||
AllowPrivate = lists:prefix(Qual, Current),
|
AllowPrivate = lists:prefix(Qual, Current),
|
||||||
@ -376,7 +409,11 @@ lookup_env1(#env{ namespace = Current, scopes = Scopes }, Kind, Ann, QName) ->
|
|||||||
{Ann1, _} = E ->
|
{Ann1, _} = E ->
|
||||||
%% Check that it's not private (or we can see private funs)
|
%% Check that it's not private (or we can see private funs)
|
||||||
case not is_private(Ann1) orelse AllowPrivate of
|
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
|
false -> false
|
||||||
end
|
end
|
||||||
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),
|
{Env1, Code1} = infer_contract_top(push_scope(namespace, Name, Env), namespace, Code, Options),
|
||||||
Namespace1 = {namespace, Ann, Name, Code1},
|
Namespace1 = {namespace, Ann, Name, Code1},
|
||||||
infer1(pop_scope(Env1), Rest, [Namespace1 | Acc], Options);
|
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(check_usings(Env, Using), Rest, Acc, Options);
|
||||||
infer1(Env, [{pragma, _, _} | Rest], Acc, Options) ->
|
infer1(Env, [{pragma, _, _} | Rest], Acc, Options) ->
|
||||||
%% Pragmas are checked in check_modifiers
|
%% Pragmas are checked in check_modifiers
|
||||||
@ -872,7 +909,7 @@ infer_contract(Env0, What, Defs0, Options) ->
|
|||||||
({letfun, _, _, _, _, _}) -> function;
|
({letfun, _, _, _, _, _}) -> function;
|
||||||
({fun_clauses, _, _, _, _}) -> function;
|
({fun_clauses, _, _, _, _}) -> function;
|
||||||
({fun_decl, _, _, _}) -> prototype;
|
({fun_decl, _, _, _}) -> prototype;
|
||||||
({using, _, _, _}) -> using;
|
({using, _, _, _, _}) -> using;
|
||||||
(_) -> unexpected
|
(_) -> unexpected
|
||||||
end,
|
end,
|
||||||
Get = fun(K, In) -> [ Def || Def <- In, Kind(Def) == K ] 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, []) ->
|
check_usings(Env, []) ->
|
||||||
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
|
AliasName = case Alias of
|
||||||
none ->
|
none ->
|
||||||
none;
|
none;
|
||||||
@ -1020,10 +1057,27 @@ check_usings(Env = #env{ used_namespaces = UsedNamespaces }, [{using, Ann, Con,
|
|||||||
create_type_errors(),
|
create_type_errors(),
|
||||||
type_error({using_undefined_namespace, Ann, qname(Con)}),
|
type_error({using_undefined_namespace, Ann, qname(Con)}),
|
||||||
destroy_and_report_type_errors(Env);
|
destroy_and_report_type_errors(Env);
|
||||||
_ ->
|
Scope ->
|
||||||
check_usings(Env#env{ used_namespaces = UsedNamespaces ++ [{qname(Con), AliasName}] }, Rest)
|
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;
|
end;
|
||||||
check_usings(Env, Using = {using, _, _, _}) ->
|
check_usings(Env, Using = {using, _, _, _, _}) ->
|
||||||
check_usings(Env, [Using]).
|
check_usings(Env, [Using]).
|
||||||
|
|
||||||
check_unexpected(Xs) ->
|
check_unexpected(Xs) ->
|
||||||
@ -1055,7 +1109,7 @@ check_modifiers_(Env, [{namespace, _, _, Decls} | Rest]) ->
|
|||||||
check_modifiers_(Env, [{pragma, Ann, Pragma} | Rest]) ->
|
check_modifiers_(Env, [{pragma, Ann, Pragma} | Rest]) ->
|
||||||
check_pragma(Env, Ann, Pragma),
|
check_pragma(Env, Ann, Pragma),
|
||||||
check_modifiers_(Env, Rest);
|
check_modifiers_(Env, Rest);
|
||||||
check_modifiers_(Env, [{using, _, _, _} | Rest]) ->
|
check_modifiers_(Env, [{using, _, _, _, _} | Rest]) ->
|
||||||
check_modifiers_(Env, Rest);
|
check_modifiers_(Env, Rest);
|
||||||
check_modifiers_(Env, [Decl | Rest]) ->
|
check_modifiers_(Env, [Decl | Rest]) ->
|
||||||
type_error({bad_top_level_decl, Decl}),
|
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}, _}} =
|
{'case', _, NewPattern, {typed, _, {block, _, NewRest}, _}} =
|
||||||
infer_case(Env, Attrs, Pattern, PatType, {block, Attrs, Rest}, BlockType),
|
infer_case(Env, Attrs, Pattern, PatType, {block, Attrs, Rest}, BlockType),
|
||||||
[{letval, Attrs, NewPattern, NewE}|NewRest];
|
[{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(check_usings(Env, Using), Attrs, Rest, BlockType);
|
||||||
infer_block(Env, Attrs, [E|Rest], BlockType) ->
|
infer_block(Env, Attrs, [E|Rest], BlockType) ->
|
||||||
[infer_expr(Env, E)|infer_block(Env, Attrs, 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}) ->
|
mk_error({using_undefined_namespace, Ann, Namespace}) ->
|
||||||
Msg = io_lib:format("Cannot use undefined namespace ~s", [Namespace]),
|
Msg = io_lib:format("Cannot use undefined namespace ~s", [Namespace]),
|
||||||
mk_t_err(pos(Ann), Msg);
|
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) ->
|
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).
|
||||||
|
Loading…
x
Reference in New Issue
Block a user