Skip to content

Commit 0b95ca4

Browse files
authored
Translate with/1 as a closure (#13299)
* Translate with/1 as a closure * Emit leaner code on with var <-
1 parent 5e13403 commit 0b95ca4

File tree

2 files changed

+35
-36
lines changed

2 files changed

+35
-36
lines changed

lib/elixir/src/elixir_clauses.erl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,16 @@ with(Meta, Args, S, E) ->
169169

170170
{{with, Meta, EExprs ++ [[{do, EDo} | EOpts]]}, S3, E}.
171171

172-
expand_with({'<-', Meta, [Left, Right]}, {S, E, _HasMatch}) ->
172+
expand_with({'<-', Meta, [Left, Right]}, {S, E, HasMatch}) ->
173173
{ERight, SR, ER} = elixir_expand:expand(Right, S, E),
174174
SM = elixir_env:reset_read(SR, S),
175175
{[ELeft], SL, EL} = head([Left], SM, ER),
176-
{{'<-', Meta, [ELeft, ERight]}, {SL, EL, true}};
176+
NewHasMatch =
177+
case ELeft of
178+
{Var, _, Ctx} when is_atom(Var), is_atom(Ctx) -> HasMatch;
179+
_ -> true
180+
end,
181+
{{'<-', Meta, [ELeft, ERight]}, {SL, EL, NewHasMatch}};
177182
expand_with(Expr, {S, E, HasMatch}) ->
178183
{EExpr, SE, EE} = elixir_expand:expand(Expr, S, E),
179184
{EExpr, {SE, EE, HasMatch}}.

lib/elixir/src/elixir_erl_pass.erl

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,15 @@ translate({for, Meta, [_ | _] = Args}, _Ann, S) ->
185185
elixir_erl_for:translate(Meta, Args, S);
186186

187187
translate({with, Meta, [_ | _] = Args}, _Ann, S) ->
188+
Ann = ?ann(Meta),
188189
{Exprs, [{do, Do} | Opts]} = elixir_utils:split_last(Args),
189-
{ElseClause, SE} = translate_with_else(Meta, Opts, S),
190-
translate_with_do(Exprs, ?ann(Meta), Do, ElseClause, SE);
190+
{ElseClause, MaybeFun, SE} = translate_with_else(Meta, Opts, S),
191+
{Case, SD} = translate_with_do(Exprs, Ann, Do, ElseClause, SE),
192+
193+
case MaybeFun of
194+
nil -> {Case, SD};
195+
FunAssign -> {{block, Ann, [FunAssign, Case]}, SD}
196+
end;
191197

192198
%% Variables
193199

@@ -400,58 +406,46 @@ returns_boolean(Condition, Body) ->
400406
%% with
401407

402408
translate_with_else(Meta, [], S) ->
403-
Generated = ?ann(?generated(Meta)),
409+
Ann = ?ann(Meta),
404410
{VarName, SC} = elixir_erl_var:build('_', S),
405-
Var = {var, Generated, VarName},
406-
{{clause, Generated, [Var], [], [Var]}, SC};
411+
Var = {var, Ann, VarName},
412+
{{clause, Ann, [Var], [], [Var]}, nil, SC};
407413
translate_with_else(Meta, [{'else', [{'->', _, [[{Var, VarMeta, Kind}], Clause]}]}], S) when is_atom(Var), is_atom(Kind) ->
408414
Ann = ?ann(Meta),
409-
Generated = erl_anno:set_generated(true, Ann),
410415
{ElseVarErl, SV} = elixir_erl_var:translate(VarMeta, Var, Kind, S#elixir_erl{context=match}),
411416
{TranslatedClause, SC} = translate(Clause, Ann, SV#elixir_erl{context=nil}),
412-
{{clause, Generated, [ElseVarErl], [], [TranslatedClause]}, SC};
417+
Clauses = [{clause, Ann, [ElseVarErl], [], [TranslatedClause]}],
418+
with_else_closure(Meta, Clauses, SC);
413419
translate_with_else(Meta, [{'else', Else}], S) ->
414420
Generated = ?generated(Meta),
415-
{ElseVarEx, ElseVarErl, SE} = elixir_erl_var:assign(Generated, S),
416-
{RaiseVar, _, SV} = elixir_erl_var:assign(Generated, SE),
421+
{RaiseVar, _, SV} = elixir_erl_var:assign(Generated, S),
417422

418423
RaiseExpr = {{'.', Generated, [erlang, error]}, Generated, [{else_clause, RaiseVar}]},
419424
RaiseClause = {'->', Generated, [[RaiseVar], RaiseExpr]},
420-
GeneratedElse = [build_generated_clause(Generated, ElseClause) || ElseClause <- Else],
421425

422-
Case = {'case', Generated, [ElseVarEx, [{do, GeneratedElse ++ [RaiseClause]}]]},
423-
{TranslatedCase, SC} = translate(Case, ?ann(Meta), SV),
424-
{{clause, ?ann(Generated), [ElseVarErl], [], [TranslatedCase]}, SC}.
425-
426-
build_generated_clause(Generated, {'->', _, [Args, Clause]}) ->
427-
NewArgs = [build_generated_clause_arg(Generated, Arg) || Arg <- Args],
428-
{'->', Generated, [NewArgs, Clause]}.
429-
430-
build_generated_clause_arg(Generated, Arg) ->
431-
{Expr, Guards} = elixir_utils:extract_guards(Arg),
432-
NewGuards = [build_generated_guard(Generated, Guard) || Guard <- Guards],
433-
concat_guards(Generated, Expr, NewGuards).
434-
435-
build_generated_guard(Generated, {{'.', _, _} = Call, _, Args}) ->
436-
{Call, Generated, [build_generated_guard(Generated, Arg) || Arg <- Args]};
437-
build_generated_guard(_, Expr) ->
438-
Expr.
439-
440-
concat_guards(_Meta, Expr, []) ->
441-
Expr;
442-
concat_guards(Meta, Expr, [Guard | Tail]) ->
443-
{'when', Meta, [Expr, concat_guards(Meta, Guard, Tail)]}.
426+
Clauses = elixir_erl_clauses:get_clauses('else', [{'else', Else ++ [RaiseClause]}], match),
427+
{TranslatedClauses, SC} = elixir_erl_clauses:clauses(Clauses, SV),
428+
with_else_closure(Meta, TranslatedClauses, SC).
444429

430+
with_else_closure(Meta, TranslatedClauses, S) ->
431+
Ann = ?ann(Meta),
432+
{_, FunErlVar, SC} = elixir_erl_var:assign(Meta, S),
433+
{_, ArgErlVar, SA} = elixir_erl_var:assign(Meta, SC),
434+
FunAssign = {match, Ann, FunErlVar, {'fun', Ann, {clauses, TranslatedClauses}}},
435+
FunCall = {call, Ann, FunErlVar, [ArgErlVar]},
436+
{{clause, Ann, [ArgErlVar], [], [FunCall]}, FunAssign, SA}.
437+
438+
translate_with_do([{'<-', Meta, [{Var, _, Ctx} = Left, Expr]} | Rest], Ann, Do, Else, S) when is_atom(Var), is_atom(Ctx) ->
439+
translate_with_do([{'=', Meta, [Left, Expr]} | Rest], Ann, Do, Else, S);
445440
translate_with_do([{'<-', Meta, [Left, Expr]} | Rest], _Ann, Do, Else, S) ->
446441
Ann = ?ann(Meta),
447442
{Args, Guards} = elixir_utils:extract_guards(Left),
448443
{TExpr, SR} = translate(Expr, Ann, S),
449444
{TArgs, SA} = elixir_erl_clauses:match(Ann, fun translate/3, Args, SR),
450445
TGuards = elixir_erl_clauses:guards(Ann, Guards, SA#elixir_erl.extra_guards, SA),
451446
{TBody, SB} = translate_with_do(Rest, Ann, Do, Else, SA#elixir_erl{extra_guards=[]}),
452-
453447
Clause = {clause, Ann, [TArgs], TGuards, unblock(TBody)},
454-
{{'case', erl_anno:set_generated(true, Ann), TExpr, [Clause, Else]}, SB};
448+
{{'case', Ann, TExpr, [Clause, Else]}, SB};
455449
translate_with_do([Expr | Rest], Ann, Do, Else, S) ->
456450
{TExpr, TS} = translate(Expr, Ann, S),
457451
{TRest, RS} = translate_with_do(Rest, Ann, Do, Else, TS),

0 commit comments

Comments
 (0)