diff options
author | Björn Gustavsson <[email protected]> | 2010-05-21 16:00:21 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2010-05-31 14:58:27 +0200 |
commit | 7ff117e24a97ce98ac13671ea140c45a67400b5d (patch) | |
tree | 7f2d7ab72be28b2630eb46c6d35f7b0233c9bef6 | |
parent | 56f23b4aca7c8bfcceeb0095536926ddb1a8102c (diff) | |
download | otp-7ff117e24a97ce98ac13671ea140c45a67400b5d.tar.gz otp-7ff117e24a97ce98ac13671ea140c45a67400b5d.tar.bz2 otp-7ff117e24a97ce98ac13671ea140c45a67400b5d.zip |
Add erlang:nif_error/1,2
A stub function that is supposed to be replaced by a NIF usually
calls erlang:error/1 to cause an exception if the NIF library
is not loaded. For example:
foo() ->
erlang:error(nif_not_loaded).
The problem is that although erlang:error/1 will normally never be
called, Dialyzer will think that any call to the function will fail
and thus generate false warnings. Adding a spec for the function
will not help because Dialyzer will not believe the spec.
Add erlang:nif_error/1,2 that work exactly like erlang:error/1,2.
Define the return types for both BIFs to be t_any().
erlang:nif_error is used like this:
-spec foo() -> binary().
foo() ->
erlang:nif_error(nif_not_loaded).
(The -spec is optional but highly recommended, since Dialyzer
otherwise has no chance to figure out the types.)
-rw-r--r-- | erts/doc/src/erlang.xml | 31 | ||||
-rw-r--r-- | erts/emulator/beam/bif.c | 28 | ||||
-rw-r--r-- | erts/emulator/beam/bif.tab | 3 | ||||
-rw-r--r-- | lib/hipe/cerl/erl_bif_types.erl | 8 |
4 files changed, 70 insertions, 0 deletions
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index e683f161f1..7ff52c5b50 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -2644,6 +2644,37 @@ os_prompt%</pre> </desc> </func> <func> + <name>erlang:nif_error(Reason)</name> + <fsummary>Stop execution with a given reason</fsummary> + <type> + <v>Reason = term()</v> + </type> + <desc> + <p>Works exactly like + <seealso marker="#error/1">erlang:error/1</seealso>, + but Dialyzer thinks that this BIF will return an arbitrary term. + When used in a stub function for a NIF to generate an + exception when the NIF library is not loaded, Dialyzer + will not generate false warnings.</p> + </desc> + </func> + <func> + <name>erlang:nif_error(Reason, Args)</name> + <fsummary>Stop execution with a given reason</fsummary> + <type> + <v>Reason = term()</v> + <v>Args = [term()]</v> + </type> + <desc> + <p>Works exactly like + <seealso marker="#error/2">erlang:error/2</seealso>, + but Dialyzer thinks that this BIF will return an arbitrary term. + When used in a stub function for a NIF to generate an + exception when the NIF library is not loaded, Dialyzer + will not generate false warnings.</p> + </desc> + </func> + <func> <name>node() -> Node</name> <fsummary>Name of the local node</fsummary> <type> diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 85bf584337..7a69dc6eff 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -1132,6 +1132,34 @@ BIF_RETTYPE error_2(Process* p, Eterm value, Eterm args) } /**********************************************************************/ +/* + * This is like exactly like error/1. The only difference is + * that Dialyzer thinks that it it will return an arbitrary term. + * It is useful in stub functions for NIFs. + */ + +BIF_RETTYPE nif_error_1(Process* p, Eterm term) +{ + p->fvalue = term; + BIF_ERROR(p, EXC_ERROR); +} + +/**********************************************************************/ +/* + * This is like exactly like error/2. The only difference is + * that Dialyzer thinks that it it will return an arbitrary term. + * It is useful in stub functions for NIFs. + */ + +BIF_RETTYPE nif_error_2(Process* p, Eterm value, Eterm args) +{ + Eterm* hp = HAlloc(p, 3); + + p->fvalue = TUPLE2(hp, value, args); + BIF_ERROR(p, EXC_ERROR_2); +} + +/**********************************************************************/ /* this is like throw/1 except that we set freason to EXC_EXIT */ BIF_RETTYPE exit_1(BIF_ALIST_1) diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 9feb302a3d..e4713567de 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -793,6 +793,9 @@ bif binary:encode_unsigned/2 bif binary:decode_unsigned/1 bif binary:decode_unsigned/2 +bif erlang:nif_error/1 +bif erlang:nif_error/2 + # # Obsolete # diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index be3073c0e6..523c00b2be 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -1155,6 +1155,10 @@ type(erlang, monitor_node, 2, Xs) -> type(erlang, monitor_node, 3, Xs) -> strict(arg_types(erlang, monitor_node, 3), Xs, fun (_) -> t_atom('true') end); +type(erlang, nif_error, 1, _) -> + t_any(); +type(erlang, nif_error, 2, Xs) -> + strict(arg_types(erlang, nif_error, 2), Xs, fun (_) -> t_any() end); type(erlang, node, 0, _) -> t_node(); type(erlang, node, 1, Xs) -> strict(arg_types(erlang, node, 1), Xs, fun (_) -> t_node() end); @@ -3628,6 +3632,10 @@ arg_types(erlang, monitor_node, 2) -> [t_node(), t_boolean()]; arg_types(erlang, monitor_node, 3) -> [t_node(), t_boolean(), t_list(t_atom('allow_passive_connect'))]; +arg_types(erlang, nif_error, 1) -> + [t_any()]; +arg_types(erlang, nif_error, 2) -> + [t_any(), t_list()]; arg_types(erlang, node, 0) -> []; arg_types(erlang, node, 1) -> |