aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2014-02-04 09:19:39 +0100
committerBjörn Gustavsson <[email protected]>2014-02-04 10:19:55 +0100
commit5d1471fae699fed9318ea6cad939156c2775d8be (patch)
tree32723185e8a5a69210fe41a1e3dc7ec721a7c9de /lib/compiler/src
parentf7663318a618d7f18f0c1aa07a023f3f7353c0af (diff)
downloadotp-5d1471fae699fed9318ea6cad939156c2775d8be.tar.gz
otp-5d1471fae699fed9318ea6cad939156c2775d8be.tar.bz2
otp-5d1471fae699fed9318ea6cad939156c2775d8be.zip
sys_core_fold: Prevent case expressions from being evaluated twice
In e12b7d5331c58b41db06cadfa4af75b78b62a2b1, a bug was introduced that would cause case expressions to be evaluated more than once if there were aliases in the pattern. Example: X = Y = io:put_chars("some chars"), {X,Y} That would be rewritten to code similar to (but in Core Erlang): X = io:put_chars("some chars"), X = io:put_chars("some chars"), {X,Y} Make sure that we only evalute the expression once by doing a transformation similar to (but in Core Erlang): NewVar = io:put_chars("some chars"), X = NewVar, Y = NewVar, {X,Y} Reported-by: José Valim Reported-by: Anthony Ramine
Diffstat (limited to 'lib/compiler/src')
-rw-r--r--lib/compiler/src/sys_core_fold.erl25
1 files changed, 23 insertions, 2 deletions
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 1cdbac5693..b7bbf40b4a 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -1925,9 +1925,30 @@ eval_case(#c_case{arg=E,clauses=[#c_clause{pats=Ps0,body=B}]}, Sub) ->
true -> cerl:values_es(E);
false -> [E]
end,
- {true,Bs} = cerl_clauses:match_list(Ps0, Es),
+ %% Consider:
+ %%
+ %% case SomeSideEffect() of
+ %% X=Y -> ...
+ %% end
+ %%
+ %% We must not rewrite it to:
+ %%
+ %% let <X,Y> = <SomeSideEffect(),SomeSideEffect()> in ...
+ %%
+ %% because SomeSideEffect() would be called evaluated twice.
+ %%
+ %% Instead we must evaluate the case expression in an outer let
+ %% like this:
+ %%
+ %% let NewVar = SomeSideEffect() in
+ %% let <X,Y> = <NewVar,NewVar> in ...
+ %%
+ Vs = make_vars([], length(Es)),
+ {true,Bs} = cerl_clauses:match_list(Ps0, Vs),
{Ps,As} = unzip(Bs),
- expr(#c_let{vars=Ps,arg=core_lib:make_values(As),body=B}, sub_new(Sub));
+ InnerLet = cerl:c_let(Ps, core_lib:make_values(As), B),
+ Let = cerl:c_let(Vs, E, InnerLet),
+ expr(Let, sub_new(Sub));
eval_case(Case, _) -> Case.
%% case_opt(CaseArg, [Clause]) -> {CaseArg,[Clause]}.