@@ -253,45 +253,8 @@ expand({'try', Meta, [Opts]}, S, E) ->
253
253
254
254
% % Comprehensions
255
255
256
- expand ({for , Meta , [_ | _ ] = Args }, S , E ) ->
257
- assert_no_match_or_guard_scope (Meta , " for" , S , E ),
258
-
259
- {Cases , Block } =
260
- case elixir_utils :split_last (Args ) of
261
- {OuterCases , OuterOpts } when is_list (OuterOpts ) ->
262
- case elixir_utils :split_last (OuterCases ) of
263
- {InnerCases , InnerOpts } when is_list (InnerOpts ) ->
264
- {InnerCases , InnerOpts ++ OuterOpts };
265
- _ ->
266
- {OuterCases , OuterOpts }
267
- end ;
268
- _ ->
269
- {Args , []}
270
- end ,
271
-
272
- validate_opts (Meta , for , [do , into , uniq , reduce ], Block , E ),
273
-
274
- {Expr , Opts } =
275
- case lists :keytake (do , 1 , Block ) of
276
- {value , {do , Do }, DoOpts } ->
277
- {Do , DoOpts };
278
- false ->
279
- form_error (Meta , E , ? MODULE , {missing_option , for , [do ]})
280
- end ,
281
-
282
- {EOpts , SO , EO } = expand (Opts , elixir_env :reset_unused_vars (S ), E ),
283
- {ECases , SC , EC } = mapfold (fun expand_for /3 , SO , EO , Cases ),
284
- assert_generator_start (Meta , ECases , E ),
285
-
286
- {EExpr , SE , EE } =
287
- case validate_for_options (EOpts , false , false , false ) of
288
- {ok , MaybeReduce } -> expand_for_do_block (Meta , Expr , SC , EC , MaybeReduce );
289
- {error , Error } -> form_error (Meta , E , ? MODULE , Error )
290
- end ,
291
-
292
- {{for , Meta , ECases ++ [[{do , EExpr } | EOpts ]]},
293
- elixir_env :merge_and_check_unused_vars (SE , S , EE ),
294
- E };
256
+ expand ({for , _ , [_ | _ ] } = Expr , S , E ) ->
257
+ expand_for (Expr , S , E , true );
295
258
296
259
% % With
297
260
@@ -563,6 +526,12 @@ expand_block([], Acc, _Meta, S, E) ->
563
526
expand_block ([H ], Acc , Meta , S , E ) ->
564
527
{EH , SE , EE } = expand (H , S , E ),
565
528
expand_block ([], [EH | Acc ], Meta , SE , EE );
529
+ expand_block ([{for , _ , [_ | _ ]} = H | T ], Acc , Meta , S , E ) ->
530
+ {EH , SE , EE } = expand_for (H , S , E , false ),
531
+ expand_block (T , [EH | Acc ], Meta , SE , EE );
532
+ expand_block ([{'=' , _ , [{'_' , _ , Ctx }, {for , _ , [_ | _ ]} = H ]} | T ], Acc , Meta , S , E ) when is_atom (Ctx ) ->
533
+ {EH , SE , EE } = expand_for (H , S , E , false ),
534
+ expand_block (T , [EH | Acc ], Meta , SE , EE );
566
535
expand_block ([H | T ], Acc , Meta , S , E ) ->
567
536
{EH , SE , EE } = expand (H , S , E ),
568
537
@@ -741,18 +710,65 @@ generated_case_clauses([{do, Clauses}]) ->
741
710
742
711
% % Comprehensions
743
712
744
- validate_for_options ([{into , _ } = Pair | Opts ], _Into , Uniq , Reduce ) ->
745
- validate_for_options (Opts , Pair , Uniq , Reduce );
746
- validate_for_options ([{uniq , Boolean } = Pair | Opts ], Into , _Uniq , Reduce ) when is_boolean (Boolean ) ->
747
- validate_for_options (Opts , Into , Pair , Reduce );
748
- validate_for_options ([{uniq , Value } | _ ], _ , _ , _ ) ->
713
+ expand_for ({for , Meta , [_ | _ ] = Args }, S , E , Return ) ->
714
+ assert_no_match_or_guard_scope (Meta , " for" , S , E ),
715
+
716
+ {Cases , Block } =
717
+ case elixir_utils :split_last (Args ) of
718
+ {OuterCases , OuterOpts } when is_list (OuterOpts ) ->
719
+ case elixir_utils :split_last (OuterCases ) of
720
+ {InnerCases , InnerOpts } when is_list (InnerOpts ) ->
721
+ {InnerCases , InnerOpts ++ OuterOpts };
722
+ _ ->
723
+ {OuterCases , OuterOpts }
724
+ end ;
725
+ _ ->
726
+ {Args , []}
727
+ end ,
728
+
729
+ validate_opts (Meta , for , [do , into , uniq , reduce ], Block , E ),
730
+
731
+ {Expr , Opts } =
732
+ case lists :keytake (do , 1 , Block ) of
733
+ {value , {do , Do }, DoOpts } ->
734
+ {Do , DoOpts };
735
+ false ->
736
+ form_error (Meta , E , ? MODULE , {missing_option , for , [do ]})
737
+ end ,
738
+
739
+ {EOpts , SO , EO } = expand (Opts , elixir_env :reset_unused_vars (S ), E ),
740
+ {ECases , SC , EC } = mapfold (fun expand_for_generator /3 , SO , EO , Cases ),
741
+ assert_generator_start (Meta , ECases , E ),
742
+
743
+ {{EExpr , SE , EE }, NormalizedOpts } =
744
+ case validate_for_options (EOpts , false , false , false , Return , Meta , E , []) of
745
+ {ok , MaybeReduce , NOpts } -> {expand_for_do_block (Meta , Expr , SC , EC , MaybeReduce ), NOpts };
746
+ {error , Error } -> {form_error (Meta , E , ? MODULE , Error ), EOpts }
747
+ end ,
748
+
749
+ {{for , Meta , ECases ++ [[{do , EExpr } | NormalizedOpts ]]},
750
+ elixir_env :merge_and_check_unused_vars (SE , S , EE ),
751
+ E }.
752
+
753
+ validate_for_options ([{into , _ } = Pair | Opts ], _Into , Uniq , Reduce , Return , Meta , E , Acc ) ->
754
+ validate_for_options (Opts , Pair , Uniq , Reduce , Return , Meta , E , [Pair | Acc ]);
755
+ validate_for_options ([{uniq , Boolean } = Pair | Opts ], Into , _Uniq , Reduce , Return , Meta , E , Acc ) when is_boolean (Boolean ) ->
756
+ validate_for_options (Opts , Into , Pair , Reduce , Return , Meta , E , [Pair | Acc ]);
757
+ validate_for_options ([{uniq , Value } | _ ], _ , _ , _ , _ , _ , _ , _ ) ->
749
758
{error , {for_invalid_uniq , Value }};
750
- validate_for_options ([{reduce , _ } = Pair | Opts ], Into , Uniq , _Reduce ) ->
751
- validate_for_options (Opts , Into , Uniq , Pair );
752
- validate_for_options ([], Into , Uniq , {reduce , _ }) when Into /= false ; Uniq /= false ->
759
+ validate_for_options ([{reduce , _ } = Pair | Opts ], Into , Uniq , _Reduce , Return , Meta , E , Acc ) ->
760
+ validate_for_options (Opts , Into , Uniq , Pair , Return , Meta , E , [ Pair | Acc ] );
761
+ validate_for_options ([], Into , Uniq , {reduce , _ }, _Return , _Meta , _E , _Acc ) when Into /= false ; Uniq /= false ->
753
762
{error , for_conflicting_reduce_into_uniq };
754
- validate_for_options ([], _Into , _Uniq , Reduce ) ->
755
- {ok , Reduce }.
763
+ validate_for_options ([], _Into = false , Uniq , Reduce = false , Return = true , Meta , E , Acc ) ->
764
+ Pair = {into , []},
765
+ validate_for_options ([Pair ], Pair , Uniq , Reduce , Return , Meta , E , Acc );
766
+ validate_for_options ([], Into = false , {uniq , true }, Reduce = false , Return = false , Meta , E , Acc ) ->
767
+ elixir_errors :form_warn (Meta , E , ? MODULE , for_with_unused_uniq ),
768
+ AccWithoutUniq = lists :keydelete (uniq , 1 , Acc ),
769
+ validate_for_options ([], Into , false , Reduce , Return , Meta , E , AccWithoutUniq );
770
+ validate_for_options ([], _Into , _Uniq , Reduce , _Return , _Meta , _E , Acc ) ->
771
+ {ok , Reduce , lists :reverse (Acc )}.
756
772
757
773
expand_for_do_block (Meta , [{'->' , _ , _ } | _ ], _S , E , false ) ->
758
774
form_error (Meta , E , ? MODULE , for_without_reduce_bad_block );
@@ -1031,12 +1047,12 @@ expand_aliases({'__aliases__', Meta, _} = Alias, S, E, Report) ->
1031
1047
1032
1048
% % Comprehensions
1033
1049
1034
- expand_for ({'<-' , Meta , [Left , Right ]}, S , E ) ->
1050
+ expand_for_generator ({'<-' , Meta , [Left , Right ]}, S , E ) ->
1035
1051
{ERight , SR , ER } = expand (Right , S , E ),
1036
1052
SM = elixir_env :reset_read (SR , S ),
1037
1053
{[ELeft ], SL , EL } = elixir_clauses :head ([Left ], SM , ER ),
1038
1054
{{'<-' , Meta , [ELeft , ERight ]}, SL , EL };
1039
- expand_for ({'<<>>' , Meta , Args } = X , S , E ) when is_list (Args ) ->
1055
+ expand_for_generator ({'<<>>' , Meta , Args } = X , S , E ) when is_list (Args ) ->
1040
1056
case elixir_utils :split_last (Args ) of
1041
1057
{LeftStart , {'<-' , OpMeta , [LeftEnd , Right ]}} ->
1042
1058
{ERight , SR , ER } = expand (Right , S , E ),
@@ -1048,7 +1064,7 @@ expand_for({'<<>>', Meta, Args} = X, S, E) when is_list(Args) ->
1048
1064
_ ->
1049
1065
expand (X , S , E )
1050
1066
end ;
1051
- expand_for (X , S , E ) ->
1067
+ expand_for_generator (X , S , E ) ->
1052
1068
expand (X , S , E ).
1053
1069
1054
1070
assert_generator_start (_ , [{'<-' , _ , [_ , _ ]} | _ ], _ ) ->
@@ -1170,6 +1186,8 @@ format_error(for_without_reduce_bad_block) ->
1170
1186
" the do block was written using acc -> expr clauses but the :reduce option was not given" ;
1171
1187
format_error (for_generator_start ) ->
1172
1188
" for comprehensions must start with a generator" ;
1189
+ format_error (for_with_unused_uniq ) ->
1190
+ " the :uniq option has no effect since the result of the for comprehension is not used" ;
1173
1191
format_error (unhandled_arrow_op ) ->
1174
1192
" unhandled operator ->" ;
1175
1193
format_error (as_in_multi_alias_call ) ->
0 commit comments