Skip to content

Commit 30d4c45

Browse files
committed
sys_core_fold: Always optimize bodies in move_let_into_expr
1 parent 97d0bb0 commit 30d4c45

File tree

2 files changed

+46
-15
lines changed

2 files changed

+46
-15
lines changed

lib/compiler/src/sys_core_fold.erl

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,7 +2198,8 @@ simplify_let(#c_let{arg=Arg}=Let, Sub) ->
21982198
move_let_into_expr(Let, Arg, Sub).
21992199

22002200
move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner0,
2201-
#c_let{vars=OuterVs0,arg=Arg0,body=OuterBody0}=Outer, Sub0) ->
2201+
#c_let{vars=OuterVs0,arg=OuterArg0,body=OuterBody0}=Outer0,
2202+
Sub0) ->
22022203
%%
22032204
%% let <InnerVars> = let <OuterVars> = <Arg>
22042205
%% in <OuterBody>
@@ -2210,29 +2211,33 @@ move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner0,
22102211
%% in let <InnerVars> = <OuterBody>
22112212
%% in <InnerBody>
22122213
%%
2213-
Arg = body(Arg0, Sub0),
2214+
OuterArg = body(OuterArg0, Sub0),
22142215
ScopeSub0 = sub_subst_scope(Sub0#sub{t=#{}}),
2215-
{OuterVs,ScopeSub} = var_list(OuterVs0, ScopeSub0),
22162216

2217+
{OuterVs,ScopeSub} = var_list(OuterVs0, ScopeSub0),
22172218
OuterBody = body(OuterBody0, ScopeSub),
22182219

2220+
{InnerVs,Sub} = var_list(InnerVs0, Sub0),
2221+
InnerBody = body(InnerBody0, Sub),
2222+
22192223
case will_fail(OuterBody) of
22202224
true ->
2225+
%% If the outer body is known to fail, changing
2226+
%% the structure may create unsafe code that
2227+
%% requires another iteration of the outer
2228+
%% fixpoint loop to clean it up, which is not
2229+
%% guaranteed since it runs for a limited number
2230+
%% of iterations.
22212231
%%
2222-
%% Avoid creating potentially unsafe code that
2223-
%% depends on another iteration of the outer
2224-
%% fixpoint loop to clean up. If <OuterBody>
2225-
%% consists of nested lets, we may run out of
2226-
%% iterations before the unsafe code is
2227-
%% eliminated.
2228-
%%
2229-
Inner0;
2232+
%% Note that we still need to update the bodies
2233+
%% as they might reference variables that no
2234+
%% longer exist.
2235+
Outer0 = Inner0#c_let.arg, %Assertion.
2236+
Outer = Outer0#c_let{vars=OuterVs,arg=OuterArg,body=OuterBody},
2237+
Inner0#c_let{vars=InnerVs,arg=Outer,body=InnerBody};
22302238
false ->
2231-
{InnerVs,Sub} = var_list(InnerVs0, Sub0),
2232-
InnerBody = body(InnerBody0, Sub),
2233-
22342239
Inner = Inner0#c_let{vars=InnerVs,arg=OuterBody,body=InnerBody},
2235-
Outer#c_let{vars=OuterVs,arg=Arg,body=Inner}
2240+
Outer0#c_let{vars=OuterVs,arg=OuterArg,body=Inner}
22362241
end;
22372242
move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
22382243
#c_case{arg=Cexpr0,clauses=[Ca0|Cs0]}=Case, Sub0) ->

lib/compiler/test/core_fold_SUITE.erl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,9 @@ do_receive_effect() ->
703703
nested_lets(_Config) ->
704704
{'EXIT',{{case_clause,ok},_}} = catch nested_lets_1(<<42>>),
705705
{'EXIT',{badarith,_}} = catch nested_lets_2(id(0), id(0)),
706+
{'EXIT',{badarith,_}} = catch nested_lets_3(),
707+
{'EXIT',{undef,_}} = catch nested_lets_4(),
708+
706709
ok.
707710

708711
%% GH-6572: Deeply nested `let` expressions caused `sys_core_fold` to generate
@@ -795,5 +798,28 @@ nested_lets_2(X, 0) ->
795798
nested_lets_2_f(_) ->
796799
ok.
797800

801+
nested_lets_3() ->
802+
try ((true = [X | _]) = (ok * (_ = ok))) of
803+
_ ->
804+
X
805+
after
806+
ok
807+
end.
808+
809+
nested_lets_4() ->
810+
try
811+
not (case {(_ = ok), (Y = ?MODULE:undef())} of
812+
a ->
813+
ok;
814+
0 ->
815+
ok
816+
end)
817+
of
818+
_ ->
819+
Y
820+
after
821+
ok
822+
end.
823+
798824
%%% Common utility functions.
799825
id(I) -> I.

0 commit comments

Comments
 (0)