1414translate (Meta , Args , S ) ->
1515 {Cases , [{do , Expr } | Opts ]} = elixir_utils :split_last (Args ),
1616
17+ % needs to be the original variables, excluding variables from generators
18+ InitVars = S # elixir_erl .var_names ,
19+
1720 case lists :keyfind (reduce , 1 , Opts ) of
18- {reduce , Reduce } -> translate_reduce (Meta , Cases , Expr , Reduce , S );
19- false -> translate_into (Meta , Cases , Expr , Opts , S )
21+ {reduce , Reduce } -> translate_reduce (Meta , Cases , Expr , Reduce , InitVars , S );
22+ false -> translate_into (Meta , Cases , Expr , Opts , InitVars , S )
2023 end .
2124
22- translate_reduce (Meta , Cases , Expr , Reduce , S ) ->
25+ translate_reduce (Meta , Cases , Expr , Reduce , InitVars , S ) ->
2326 Ann = ? ann (Meta ),
2427 {TReduce , SR } = elixir_erl_pass :translate (Reduce , Ann , S ),
2528 {TCases , SC } = translate_gen (Meta , Cases , [], SR ),
@@ -30,9 +33,9 @@ translate_reduce(Meta, Cases, Expr, Reduce, S) ->
3033 ({'case' , CaseAnn , _ , CaseBlock }, InnerAcc ) -> {'case' , CaseAnn , InnerAcc , CaseBlock }
3134 end ,
3235
33- build_reduce (Ann , TCases , InnerFun , TExpr , TReduce , false , SE ).
36+ build_reduce (Ann , TCases , InnerFun , TExpr , TReduce , false , InitVars , SE ).
3437
35- translate_into (Meta , Cases , Expr , Opts , S ) ->
38+ translate_into (Meta , Cases , Expr , Opts , InitVars , S ) ->
3639 Ann = ? ann (Meta ),
3740
3841 {TInto , SI } =
@@ -47,8 +50,8 @@ translate_into(Meta, Cases, Expr, Opts, S) ->
4750 {TExpr , SE } = elixir_erl_pass :translate (wrap_expr_if_unused (Expr , TInto ), Ann , SC ),
4851
4952 case inline_or_into (TInto ) of
50- inline -> build_inline (Ann , TCases , TExpr , TInto , TUniq , SE );
51- into -> build_into (Ann , TCases , TExpr , TInto , TUniq , SE )
53+ inline -> build_inline (Ann , TCases , TExpr , TInto , TUniq , InitVars , SE );
54+ into -> build_into (Ann , TCases , TExpr , TInto , TUniq , InitVars , SE )
5255 end .
5356
5457% % In case we have no return, we wrap the expression
@@ -115,29 +118,29 @@ collect_filters([H | T], Acc) ->
115118collect_filters ([], Acc ) ->
116119 {Acc , []}.
117120
118- build_inline (Ann , Clauses , Expr , Into , Uniq , S ) ->
121+ build_inline (Ann , Clauses , Expr , Into , Uniq , InitVars , S ) ->
119122 case not Uniq and lists :all (fun (Clause ) -> element (1 , Clause ) == bin end , Clauses ) of
120123 true -> {build_comprehension (Ann , Clauses , Expr , Into ), S };
121- false -> build_inline_each (Ann , Clauses , Expr , Into , Uniq , S )
124+ false -> build_inline_each (Ann , Clauses , Expr , Into , Uniq , InitVars , S )
122125 end .
123126
124- build_inline_each (Ann , Clauses , Expr , false , Uniq , S ) ->
127+ build_inline_each (Ann , Clauses , Expr , false , Uniq , InitVars , S ) ->
125128 InnerFun = fun (InnerExpr , _InnerAcc ) -> InnerExpr end ,
126- build_reduce (Ann , Clauses , InnerFun , Expr , {nil , Ann }, Uniq , S );
127- build_inline_each (Ann , [{enum , _ , Left = {var , _ , _ }, Right , [] = _Filters }], Expr , {nil , _ } = _Into , false , S ) ->
129+ build_reduce (Ann , Clauses , InnerFun , Expr , {nil , Ann }, Uniq , InitVars , S );
130+ build_inline_each (Ann , [{enum , _ , Left = {var , _ , _ }, Right , [] = _Filters }], Expr , {nil , _ } = _Into , false , _InitVars , S ) ->
128131 Clauses = [{clause , Ann , [Left ], [], [Expr ]}],
129132 Args = [Right , {'fun' , Ann , {clauses , Clauses }}],
130133 {? remote (Ann , 'Elixir.Enum' , map , Args ), S };
131- build_inline_each (Ann , [{enum , _ , Left = {var , _ , _ }, Right , [] = _Filters }], Expr , {map , _ , []} = _Into , false , S ) ->
134+ build_inline_each (Ann , [{enum , _ , Left = {var , _ , _ }, Right , [] = _Filters }], Expr , {map , _ , []} = _Into , false , _InitVars , S ) ->
132135 Clauses = [{clause , Ann , [Left ], [], [Expr ]}],
133136 Args = [Right , {'fun' , Ann , {clauses , Clauses }}],
134137 List = ? remote (Ann , 'Elixir.Enum' , map , Args ),
135138 {? remote (Ann , maps , from_list , [List ]), S };
136- build_inline_each (Ann , Clauses , Expr , {nil , _ } = Into , Uniq , S ) ->
139+ build_inline_each (Ann , Clauses , Expr , {nil , _ } = Into , Uniq , InitVars , S ) ->
137140 InnerFun = fun (InnerExpr , InnerAcc ) -> {cons , Ann , InnerExpr , InnerAcc } end ,
138- {ReduceExpr , SR } = build_reduce (Ann , Clauses , InnerFun , Expr , Into , Uniq , S ),
141+ {ReduceExpr , SR } = build_reduce (Ann , Clauses , InnerFun , Expr , Into , Uniq , InitVars , S ),
139142 {? remote (Ann , lists , reverse , [ReduceExpr ]), SR };
140- build_inline_each (Ann , Clauses , Expr , {bin , _ , []}, Uniq , S ) ->
143+ build_inline_each (Ann , Clauses , Expr , {bin , _ , []}, Uniq , InitVars , S ) ->
141144 {InnerValue , SV } = build_var (Ann , S ),
142145 Generated = erl_anno :set_generated (true , Ann ),
143146
@@ -155,17 +158,17 @@ build_inline_each(Ann, Clauses, Expr, {bin, _, []}, Uniq, S) ->
155158 ]}
156159 end ,
157160
158- {ReduceExpr , SR } = build_reduce (Ann , Clauses , InnerFun , Expr , {nil , Ann }, Uniq , SV ),
161+ {ReduceExpr , SR } = build_reduce (Ann , Clauses , InnerFun , Expr , {nil , Ann }, Uniq , InitVars , SV ),
159162 {? remote (Ann , erlang , list_to_bitstring , [ReduceExpr ]), SR }.
160163
161- build_into (Ann , Clauses , Expr , {map , _ , []}, Uniq , S ) ->
162- {ReduceExpr , SR } = build_inline_each (Ann , Clauses , Expr , {nil , Ann }, Uniq , S ),
164+ build_into (Ann , Clauses , Expr , {map , _ , []}, Uniq , InitVars , S ) ->
165+ {ReduceExpr , SR } = build_inline_each (Ann , Clauses , Expr , {nil , Ann }, Uniq , InitVars , S ),
163166 {? remote (Ann , maps , from_list , [ReduceExpr ]), SR };
164- build_into (Ann , Clauses , Expr , ? empty_map_set_pattern = _Into , Uniq , S ) ->
167+ build_into (Ann , Clauses , Expr , ? empty_map_set_pattern = _Into , Uniq , InitVars , S ) ->
165168 InnerFun = fun (InnerExpr , InnerAcc ) -> {cons , Ann , InnerExpr , InnerAcc } end ,
166- {ReduceExpr , SR } = build_reduce (Ann , Clauses , InnerFun , Expr , {nil , Ann }, Uniq , S ),
169+ {ReduceExpr , SR } = build_reduce (Ann , Clauses , InnerFun , Expr , {nil , Ann }, Uniq , InitVars , S ),
167170 {? remote (Ann , 'Elixir.MapSet' , new , [ReduceExpr ]), SR };
168- build_into (Ann , Clauses , Expr , Into , Uniq , S ) ->
171+ build_into (Ann , Clauses , Expr , Into , Uniq , InitVars , S ) ->
169172 {Fun , SF } = build_var (Ann , S ),
170173 {Acc , SA } = build_var (Ann , SF ),
171174 {Kind , SK } = build_var (Ann , SA ),
@@ -182,7 +185,7 @@ build_into(Ann, Clauses, Expr, Into, Uniq, S) ->
182185 ? remote (Ann , 'Elixir.Collectable' , into , [Into ])
183186 },
184187
185- {IntoReduceExpr , SN } = build_reduce (Ann , Clauses , InnerFun , Expr , Acc , Uniq , SD ),
188+ {IntoReduceExpr , SN } = build_reduce (Ann , Clauses , InnerFun , Expr , Acc , Uniq , InitVars , SD ),
186189
187190 TryExpr =
188191 {'try' , Ann ,
@@ -205,10 +208,10 @@ stacktrace_clause(Ann, Fun, Acc, Kind, Reason, Stack) ->
205208
206209% % Helpers
207210
208- build_reduce (Ann , Clauses , InnerFun , Expr , Into , false , S ) ->
211+ build_reduce (Ann , Clauses , InnerFun , Expr , Into , false , InitVars , S ) ->
209212 {Acc , SA } = build_var (Ann , S ),
210- {build_reduce_each (Clauses , InnerFun (Expr , Acc ), Into , Acc , SA ), SA };
211- build_reduce (Ann , Clauses , InnerFun , Expr , Into , true , S ) ->
213+ {build_reduce_each (Clauses , InnerFun (Expr , Acc ), Into , Acc , InitVars , SA ), SA };
214+ build_reduce (Ann , Clauses , InnerFun , Expr , Into , true , InitVars , S ) ->
212215 % % Those variables are used only inside the anonymous function
213216 % % so we don't need to worry about returning the scope.
214217 {Acc , SA } = build_var (Ann , S ),
@@ -229,12 +232,12 @@ build_reduce(Ann, Clauses, InnerFun, Expr, Into, true, S) ->
229232 ]}
230233 ]},
231234
232- EnumReduceCall = build_reduce_each (Clauses , InnerExpr , NewInto , Acc , SU ),
235+ EnumReduceCall = build_reduce_each (Clauses , InnerExpr , NewInto , Acc , InitVars , SU ),
233236 {? remote (Ann , erlang , element , [{integer , Ann , 1 }, EnumReduceCall ]), SU }.
234237
235- build_reduce_each ([{enum , Meta , Left , Right , Filters } | T ], Expr , Arg , Acc , S ) ->
238+ build_reduce_each ([{enum , Meta , Left , Right , Filters } | T ], Expr , Arg , Acc , InitVars , S ) ->
236239 Ann = ? ann (Meta ),
237- True = build_reduce_each (T , Expr , Acc , Acc , S ),
240+ True = build_reduce_each (T , Expr , Acc , Acc , InitVars , S ),
238241 False = Acc ,
239242 Generated = erl_anno :set_generated (true , Ann ),
240243
@@ -255,13 +258,13 @@ build_reduce_each([{enum, Meta, Left, Right, Filters} | T], Expr, Arg, Acc, S) -
255258 Args = [Right , Arg , {'fun' , Ann , {clauses , Clauses1 }}],
256259 ? remote (Ann , 'Elixir.Enum' , reduce , Args );
257260
258- build_reduce_each ([{bin , Meta , Left , Right , Filters } | T ], Expr , Arg , Acc , S ) ->
261+ build_reduce_each ([{bin , Meta , Left , Right , Filters } | T ], Expr , Arg , Acc , InitVars , S ) ->
259262 Ann = ? ann (Meta ),
260263 Generated = erl_anno :set_generated (true , Ann ),
261264 {Tail , ST } = build_var (Ann , S ),
262265 {Fun , SF } = build_var (Ann , ST ),
263266
264- True = build_reduce_each (T , Expr , Acc , Acc , SF ),
267+ True = build_reduce_each (T , Expr , Acc , Acc , InitVars , SF ),
265268 False = Acc ,
266269 {bin , _ , Elements } = Left ,
267270 TailElement = {bin_element , Ann , Tail , default , [bitstring ]},
@@ -275,7 +278,7 @@ build_reduce_each([{bin, Meta, Left, Right, Filters} | T], Expr, Arg, Acc, S) ->
275278 [? remote (Ann , erlang , error , [pair (Ann , badarg , Tail )])]}],
276279
277280 NoVarClauses =
278- case no_var (Generated , Elements ) of
281+ case no_unbound_var (Generated , Elements , InitVars ) of
279282 error ->
280283 Clauses ;
281284
@@ -294,7 +297,7 @@ build_reduce_each([{bin, Meta, Left, Right, Filters} | T], Expr, Arg, Acc, S) ->
294297 {named_fun , Ann , element (3 , Fun ), VarClauses },
295298 [Right , Arg ]};
296299
297- build_reduce_each ([], Expr , _Arg , _Acc , _S ) ->
300+ build_reduce_each ([], Expr , _Arg , _Acc , _InitVars , _S ) ->
298301 Expr .
299302
300303is_var ({var , _ , _ }) -> true ;
@@ -307,9 +310,10 @@ build_var(Ann, S) ->
307310 {Name , ST } = elixir_erl_var :build ('_' , S ),
308311 {{var , Ann , Name }, ST }.
309312
310- no_var (ParentAnn , Elements ) ->
313+ no_unbound_var (ParentAnn , Elements , InitVars ) ->
314+ Vars = #{V => K || K := V <- InitVars },
311315 try
312- [{bin_element , Ann , NoVarExpr , no_var_size (Size ), Types } ||
316+ [{bin_element , Ann , NoVarExpr , no_unbound_var_size (Size , Vars ), Types } ||
313317 {bin_element , Ann , Expr , Size , Types } <- Elements ,
314318 NoVarExpr <- no_var_expr (ParentAnn , Expr )]
315319 catch
@@ -319,9 +323,17 @@ no_var(ParentAnn, Elements) ->
319323no_var_expr (Ann , {string , _ , String }) -> [{var , Ann , '_' } || _ <- String ];
320324no_var_expr (Ann , _ ) -> [{var , Ann , '_' }].
321325
322- no_var_size (default ) -> default ;
323- no_var_size (Size ) when is_integer (Size ) -> Size ;
324- no_var_size (_ ) -> throw (unbound_size ).
326+ no_unbound_var_size (Size , Vars ) ->
327+ valid_var_size (Size , Vars ) orelse throw (unbound_size ),
328+ Size .
329+
330+ valid_var_size ({var , _ , Var }, Vars ) when is_map_key (Var , Vars ) -> true ;
331+ valid_var_size (default , _Vars ) -> true ;
332+ valid_var_size ({integer , _ , _ }, _Vars ) -> true ;
333+ valid_var_size (Size , _Vars ) when is_integer (Size ) -> true ;
334+ valid_var_size ({op , _Ann , _Op , Left , Right }, Vars ) ->
335+ valid_var_size (Left , Vars ) andalso valid_var_size (Right , Vars );
336+ valid_var_size (_Size , _vars ) -> false .
325337
326338build_comprehension (Ann , Clauses , Expr , Into ) ->
327339 {comprehension_kind (Into ), Ann , Expr , comprehension_clause (Clauses )}.
0 commit comments