aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2019-02-04 10:03:55 +0100
committerBjörn Gustavsson <[email protected]>2019-02-11 06:36:12 +0100
commit4763811e1d67a0d2ac3442d4694b4e1dee1b4364 (patch)
tree99e059b0a795e1d4716743c48a63742f0ad4a7bc /lib/stdlib
parent3542afbdc4909455ad9e45e2b5328835a838a1bd (diff)
downloadotp-4763811e1d67a0d2ac3442d4694b4e1dee1b4364.tar.gz
otp-4763811e1d67a0d2ac3442d4694b4e1dee1b4364.tar.bz2
otp-4763811e1d67a0d2ac3442d4694b4e1dee1b4364.zip
beam_ssa_type: Propagate the 'none' type from calls
Consider this pseudo code: f(...) -> Val = case Expr of ... -> ... ; ... -> ... ; ... -> my_abort(something_went_wrong) end, %% Here follows code that uses Val. . . . my_abort(Reason) -> throw({error,Reason}). The first two clauses in the case will probably provide some information about the type of the variable `Var`, information that would be useful for optimizing the code that follows the case. However, the third clause would ruin everything. The call to `my_abort/1` could return anything, and thus `Val` could also have any type. 294d66a295f6 introduced module-level type analysis, which will in general keep track of the return type of a local function call. However, it does not improve the optimization for this specific function. When a function never returns, that is, when its type is `none`, it does not propagate the `none` type, but instead pretends that the return type is `any`. This commit extends the handling of functions that don't return to properly handle the `none` type. Any instructions that directly follows the function that does not return will be discarded, and the call will be rewritten to a tail-recursive call. For this specific example, it means that the type for `Val` deduced from the first two clauses will be retained and can be used for optimizing the code after the case.
Diffstat (limited to 'lib/stdlib')
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl12
1 files changed, 11 insertions, 1 deletions
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index f4019d477b..2436c8091c 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1156,7 +1156,17 @@ simple() ->
{A}.
simple1() ->
- erlang:error(simple).
+ %% If the compiler could see that this function would always
+ %% throw an error exception, it would rewrite simple() like this:
+ %%
+ %% simple() -> simple1().
+ %%
+ %% That would change the stacktrace. To prevent the compiler from
+ %% doing that optimization, we must obfuscate the code.
+ case get(a_key_that_is_not_defined) of
+ undefined -> erlang:error(simple);
+ WillNeverHappen -> WillNeverHappen
+ end.
%% Simple cases, just to cover some code.
funs(Config) when is_list(Config) ->