Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:24
erlang
0304-dialyzer-Refine-the-type-for-erlang-raise-...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0304-dialyzer-Refine-the-type-for-erlang-raise-3.patch of Package erlang
From b3cacc27b7f8e40b6127aaada5cdd52ea802aa1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org> Date: Fri, 10 Sep 2021 09:07:17 +0200 Subject: [PATCH 1/2] dialyzer: Refine the type for erlang:raise/3 Dialyzer and Typer would assume that `erlang:raise/3` always returns `badarg`. That is a correct return value, but unless `erlang:raise/3` is given incorrect arguments, it will raise an exception. The determined type would be strange for functions where `erlang:raise/3` would always raise an exception. For example: foobar(A) -> try atom_to_list(A) catch C:Reason:Stk -> io:format("ERROR: ~p ~p\n~p\n", [C,Reason,Stk]), erlang:raise(C, Reason, Stk) end. Dialyzer and Typer would think that the spec for `foobar/1` was: -spec foobar(_) -> 'badarg' | string(). Eliminate this issue by teaching Dialyzer to figure out the correct return value or lack thereof for `erlang:raise/3` when the types of its arguments are known. The spec for `foobar/1` will now be: -spec foobar(_) -> string(). --- erts/preloaded/src/erlang.erl | 1 + lib/common_test/src/ct.erl | 4 ++++ lib/common_test/src/test_server.erl | 6 +++++ lib/dialyzer/src/erl_bif_types.erl | 22 ++++++++++++++++++- .../test/small_SUITE_data/results/try2 | 1 + lib/stdlib/src/unicode.erl | 2 ++ 6 files changed, 35 insertions(+), 1 deletion(-) diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 4164d5d7b5..f76bf8d4ae 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1796,6 +1796,7 @@ put(_Key, _Val) -> erlang:nif_error(undefined). %% raise/3 +%% Shadowed by erl_bif_types: erlang:raise/3 -spec erlang:raise(Class, Reason, Stacktrace) -> 'badarg' when Class :: 'error' | 'exit' | 'throw', Reason :: term(), diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index bfa7b25862..af3c20d20c 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -296,6 +296,8 @@ capture_get([ExclCat | ExclCategories]) -> capture_get([]) -> test_server:capture_get(). +-spec fail(term()) -> no_return(). + fail(Reason) -> try exit({test_case_failed,Reason}) @@ -308,6 +310,8 @@ fail(Reason) -> erlang:raise(Class, R, Stk) end. +-spec fail(io:format(), [term()]) -> no_return(). + fail(Format, Args) -> try io_lib:format(Format, Args) of Str -> diff --git a/lib/common_test/src/test_server.erl b/lib/common_test/src/test_server.erl index e5f6092f66..63955f83aa 100644 --- a/lib/common_test/src/test_server.erl +++ b/lib/common_test/src/test_server.erl @@ -1971,6 +1971,9 @@ adjusted_sleep(MSecs) -> %% %% Immediately calls exit. Included because test suites are easier %% to read when using this function, rather than exit directly. + +-spec fail(term()) -> no_return(). + fail(Reason) -> comment(cast_to_list(Reason)), try @@ -1995,6 +1998,9 @@ cast_to_list(X) -> lists:flatten(io_lib:format("~tp", [X])). %% %% Immediately calls exit. Included because test suites are easier %% to read when using this function, rather than exit directly. + +-spec fail() -> no_return(). + fail() -> try exit(suite_failed) diff --git a/lib/dialyzer/src/erl_bif_types.erl b/lib/dialyzer/src/erl_bif_types.erl index d755d5e3d9..8e87af5f15 100644 --- a/lib/dialyzer/src/erl_bif_types.erl +++ b/lib/dialyzer/src/erl_bif_types.erl @@ -813,6 +813,13 @@ type(erlang, node, 0, _, _Opaques) -> t_node(); %% Guard bif, needs to be here. type(erlang, node, 1, Xs, Opaques) -> strict(erlang, node, 1, Xs, fun (_) -> t_node() end, Opaques); +type(erlang, raise, 3, Xs, Opaques) -> + Ts = arg_types(erlang, raise, 3), + Xs1 = inf_lists(Xs, Ts, Opaques), + case any_is_none_or_unit(Xs1) of + true -> t_atom('badarg'); + false -> t_none() + end; %% Guard bif, needs to be here. type(erlang, round, 1, Xs, Opaques) -> strict(erlang, round, 1, Xs, fun (_) -> t_integer() end, Opaques); @@ -2312,6 +2319,20 @@ arg_types(erlang, node, 0) -> %% Guard bif, needs to be here. arg_types(erlang, node, 1) -> [t_identifier()]; +arg_types(erlang, raise, 3) -> + %% The types are based on the implementation of erlang:raise/3, not + %% the documention. That is, those are the types for which + %% erlang:raise/3 will raise an exception. If the arguments do not + %% conform to those types, erlang:raise/3 will return 'badarg'. + Class = t_sup([t_atom('error'), t_atom('exit'), t_atom('throw')]), + InfoList = t_list(), %erlang:raise/3 does not check the contents of the list. + ArityOrArgs = t_any(), %erlang:raise/3 does not check the type. + MFA = t_tuple([t_module(), t_atom(), ArityOrArgs]), + MFAS = t_tuple([t_module(), t_atom(), ArityOrArgs, InfoList]), + Fun = t_tuple([t_fun(), ArityOrArgs]), + FunI = t_tuple([t_fun(), ArityOrArgs, InfoList]), + Stack = t_list(t_sup([MFA, MFAS, Fun, FunI])), + [Class, t_any(), Stack]; %% Guard bif, needs to be here. arg_types(erlang, round, 1) -> [t_number()]; @@ -2551,7 +2572,6 @@ check_fun_application(Fun, Args, Opaques) -> error end. - %% ===================================================================== %% Some basic types used in various parts of the system %% ===================================================================== diff --git a/lib/dialyzer/test/small_SUITE_data/results/try2 b/lib/dialyzer/test/small_SUITE_data/results/try2 index 14306bb756..e3fada37ea 100644 --- a/lib/dialyzer/test/small_SUITE_data/results/try2 +++ b/lib/dialyzer/test/small_SUITE_data/results/try2 @@ -1,2 +1,3 @@ +try2.erl:12:1: Function run/2 has no local return try2.erl:33:1: Function run3/2 has no local return diff --git a/lib/stdlib/src/unicode.erl b/lib/stdlib/src/unicode.erl index 7ae5dec878..20c92a1a4a 100644 --- a/lib/stdlib/src/unicode.erl +++ b/lib/stdlib/src/unicode.erl @@ -390,6 +390,8 @@ characters_to_binary_int(ML, InEncoding) -> fake_stacktrace(Reason, characters_to_binary, [ML, InEncoding]) end. +-spec fake_stacktrace(term(), atom(), [term()]) -> no_return(). + fake_stacktrace(Reason, Name, Args) -> try error(new_stacktrace, Args) -- 2.34.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor