fix(bpapi): Use argument types from the spec

This commit is contained in:
k32 2022-01-12 15:39:15 +01:00
parent 7b65684c45
commit 04bac16741
1 changed files with 17 additions and 9 deletions

View File

@ -20,6 +20,9 @@
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
%% Using an undocumented API here :(
-include_lib("dialyzer/src/dialyzer.hrl").
-type api_dump() :: #{{emqx_bpapi:api(), emqx_bpapi:api_version()} => -type api_dump() :: #{{emqx_bpapi:api(), emqx_bpapi:api_version()} =>
#{ calls := [emqx_bpapi:rpc()] #{ calls := [emqx_bpapi:rpc()]
, casts := [emqx_bpapi:rpc()] , casts := [emqx_bpapi:rpc()]
@ -128,21 +131,24 @@ typecheck_apis( #{release := CallerRelease, api := CallerAPIs, signatures := Cal
setnok(), setnok(),
[?ERROR("Incompatible RPC call: " [?ERROR("Incompatible RPC call: "
"type of the parameter ~p of RPC call ~s on release ~p " "type of the parameter ~p of RPC call ~s on release ~p "
"is not a subtype of the target function ~s on release ~p", "is not a subtype of the target function ~s on release ~p.~n"
"Caller type: ~s~nCallee type: ~s~n",
[Var, format_call(From), CallerRelease, [Var, format_call(From), CallerRelease,
format_call(To), CalleeRelease]) format_call(To), CalleeRelease,
|| Var <- TypeErrors] erl_types:t_to_string(CallerType),
erl_types:t_to_string(CalleeType)])
|| {Var, CallerType, CalleeType} <- TypeErrors]
end end
end, end,
AllCalls). AllCalls).
-spec typecheck_rpc(param_types(), param_types()) -> [emqx_bpapi:var_name()]. -spec typecheck_rpc(param_types(), param_types()) -> [{emqx_bpapi:var_name(), _Type, _Type}].
typecheck_rpc(Caller, Callee) -> typecheck_rpc(Caller, Callee) ->
maps:fold(fun(Var, CalleeType, Acc) -> maps:fold(fun(Var, CalleeType, Acc) ->
#{Var := CallerType} = Caller, #{Var := CallerType} = Caller,
case erl_types:t_is_subtype(CallerType, CalleeType) of case erl_types:t_is_subtype(CallerType, CalleeType) of
true -> Acc; true -> Acc;
false -> [Var|Acc] false -> [{Var, CallerType, CalleeType}|Acc]
end end
end, end,
[], [],
@ -182,7 +188,7 @@ dump(Opts) ->
warn_nonbpapi_rpcs(NonBPAPICalls), warn_nonbpapi_rpcs(NonBPAPICalls),
APIDump = collect_bpapis(BPAPICalls), APIDump = collect_bpapis(BPAPICalls),
DialyzerDump = collect_signatures(PLT, APIDump), DialyzerDump = collect_signatures(PLT, APIDump),
Release = emqx_app:get_release(), [Release|_] = string:split(emqx_app:get_release(), "-"),
dump_api(#{api => APIDump, signatures => DialyzerDump, release => Release}), dump_api(#{api => APIDump, signatures => DialyzerDump, release => Release}),
xref:stop(?XREF), xref:stop(?XREF),
erase(bpapi_ok). erase(bpapi_ok).
@ -263,9 +269,11 @@ collect_signatures(PLT, APIs) ->
enrich({From0, To0}, {Acc0, PLT}) -> enrich({From0, To0}, {Acc0, PLT}) ->
From = call_to_mfa(From0), From = call_to_mfa(From0),
To = call_to_mfa(To0), To = call_to_mfa(To0),
case {dialyzer_plt:lookup(PLT, From), dialyzer_plt:lookup(PLT, To)} of case {dialyzer_plt:lookup_contract(PLT, From), dialyzer_plt:lookup(PLT, To)} of
{{value, TFrom}, {value, TTo}} -> {{value, #contract{args = FromArgs}}, {value, TTo}} ->
Acc = Acc0#{ From => TFrom %% TODO: Check return type
FromRet = erl_types:t_any(),
Acc = Acc0#{ From => {FromRet, FromArgs}
, To => TTo , To => TTo
}, },
{Acc, PLT}; {Acc, PLT};