@@ -41,17 +41,17 @@ fn_arity(Args) -> length(Args).
4141capture (Meta , {'/' , _ , [{{'.' , _ , [M , F ]} = Dot , RequireMeta , []}, A ]}, S , E ) when is_atom (F ), is_integer (A ) ->
4242 Args = args_from_arity (Meta , A , E ),
4343 handle_capture_possible_warning (Meta , RequireMeta , M , F , A , E ),
44- capture_require ({Dot , RequireMeta , Args }, S , E , true );
44+ capture_require ({Dot , RequireMeta , Args }, S , E , arity );
4545
4646capture (Meta , {'/' , _ , [{F , ImportMeta , C }, A ]}, S , E ) when is_atom (F ), is_integer (A ), is_atom (C ) ->
4747 Args = args_from_arity (Meta , A , E ),
48- capture_import ({F , ImportMeta , Args }, S , E , true );
48+ capture_import ({F , ImportMeta , Args }, S , E , arity );
4949
5050capture (_Meta , {{'.' , _ , [_ , Fun ]}, _ , Args } = Expr , S , E ) when is_atom (Fun ), is_list (Args ) ->
51- capture_require (Expr , S , E , is_sequential_and_not_empty (Args ));
51+ capture_require (Expr , S , E , check_sequential_and_not_empty (Args ));
5252
5353capture (Meta , {{'.' , _ , [_ ]}, _ , Args } = Expr , S , E ) when is_list (Args ) ->
54- capture_expr (Meta , Expr , S , E , false );
54+ capture_expr (Meta , Expr , S , E , non_sequential );
5555
5656capture (Meta , {'__block__' , _ , [Expr ]}, S , E ) ->
5757 capture (Meta , Expr , S , E );
@@ -60,31 +60,39 @@ capture(Meta, {'__block__', _, _} = Expr, _S, E) ->
6060 file_error (Meta , E , ? MODULE , {block_expr_in_capture , Expr });
6161
6262capture (_Meta , {Atom , _ , Args } = Expr , S , E ) when is_atom (Atom ), is_list (Args ) ->
63- capture_import (Expr , S , E , is_sequential_and_not_empty (Args ));
63+ capture_import (Expr , S , E , check_sequential_and_not_empty (Args ));
6464
6565capture (Meta , {Left , Right }, S , E ) ->
6666 capture (Meta , {'{}' , Meta , [Left , Right ]}, S , E );
6767
6868capture (Meta , List , S , E ) when is_list (List ) ->
69- capture_expr (Meta , List , S , E , is_sequential_and_not_empty (List ));
69+ capture_expr (Meta , List , S , E , check_sequential_and_not_empty (List ));
7070
7171capture (Meta , Integer , _S , E ) when is_integer (Integer ) ->
7272 file_error (Meta , E , ? MODULE , {capture_arg_outside_of_capture , Integer });
7373
7474capture (Meta , Arg , _S , E ) ->
7575 invalid_capture (Meta , Arg , E ).
7676
77- capture_import ({Atom , ImportMeta , Args } = Expr , S , E , Sequential ) ->
78- Res = Sequential andalso
77+ capture_import ({Atom , ImportMeta , Args } = Expr , S , E , ArgsType ) ->
78+ Res = ArgsType /= non_sequential andalso
7979 elixir_dispatch :import_function (ImportMeta , Atom , length (Args ), E ),
80- handle_capture (Res , ImportMeta , ImportMeta , Expr , S , E , Sequential ).
80+ handle_capture (Res , ImportMeta , ImportMeta , Expr , S , E , ArgsType ).
8181
82- capture_require ({{'.' , DotMeta , [Left , Right ]}, RequireMeta , Args }, S , E , Sequential ) ->
82+ capture_require ({{'.' , DotMeta , [Left , Right ]}, RequireMeta , Args }, S , E , ArgsType ) ->
8383 case escape (Left , E , []) of
8484 {EscLeft , []} ->
8585 {ELeft , SE , EE } = elixir_expand :expand (EscLeft , S , E ),
8686
87- Res = Sequential andalso case ELeft of
87+ case ELeft of
88+ _ when ArgsType /= arity -> ok ;
89+ Atom when is_atom (Atom ) -> ok ;
90+ {Var , _ , Ctx } when is_atom (Var ), is_atom (Ctx ) -> ok ;
91+ % % TODO: Raise on Elixir v2.0
92+ _ -> elixir_errors :file_warn (RequireMeta , E , ? MODULE , {complex_module_capture , Left })
93+ end ,
94+
95+ Res = ArgsType /= non_sequential andalso case ELeft of
8896 {Name , _ , Context } when is_atom (Name ), is_atom (Context ) ->
8997 {remote , ELeft , Right , length (Args )};
9098 _ when is_atom (ELeft ) ->
@@ -94,24 +102,25 @@ capture_require({{'.', DotMeta, [Left, Right]}, RequireMeta, Args}, S, E, Sequen
94102 end ,
95103
96104 Dot = {{'.' , DotMeta , [ELeft , Right ]}, RequireMeta , Args },
97- handle_capture (Res , RequireMeta , DotMeta , Dot , SE , EE , Sequential );
105+ handle_capture (Res , RequireMeta , DotMeta , Dot , SE , EE , ArgsType );
98106
99107 {EscLeft , Escaped } ->
100108 Dot = {{'.' , DotMeta , [EscLeft , Right ]}, RequireMeta , Args },
101- capture_expr (RequireMeta , Dot , S , E , Escaped , Sequential )
109+ capture_expr (RequireMeta , Dot , S , E , Escaped , ArgsType )
102110 end .
103111
104- handle_capture (false , Meta , _DotMeta , Expr , S , E , Sequential ) ->
105- capture_expr (Meta , Expr , S , E , Sequential );
106- handle_capture (LocalOrRemote , Meta , DotMeta , _Expr , S , E , _Sequential ) ->
112+ handle_capture (false , Meta , _DotMeta , Expr , S , E , ArgsType ) ->
113+ capture_expr (Meta , Expr , S , E , ArgsType );
114+ handle_capture (LocalOrRemote , Meta , DotMeta , _Expr , S , E , _ArgsType ) ->
107115 {LocalOrRemote , Meta , DotMeta , S , E }.
108116
109- capture_expr (Meta , Expr , S , E , Sequential ) ->
110- capture_expr (Meta , Expr , S , E , [], Sequential ).
111- capture_expr (Meta , Expr , S , E , Escaped , Sequential ) ->
117+ capture_expr (Meta , Expr , S , E , ArgsType ) ->
118+ capture_expr (Meta , Expr , S , E , [], ArgsType ).
119+ capture_expr (Meta , Expr , S , E , Escaped , ArgsType ) ->
112120 case escape (Expr , E , Escaped ) of
113- {_ , []} when not Sequential ->
121+ {_ , []} when ArgsType == non_sequential ->
114122 invalid_capture (Meta , Expr , E );
123+ % % TODO: Remove this clause once we raise on complex module captures like &get_mod().fun/0
115124 {{{'.' , _ , [_ , _ ]} = Dot , _ , Args }, []} ->
116125 Meta2 = lists :keydelete (no_parens , 1 , Meta ),
117126 Fn = {fn , Meta2 , [{'->' , Meta2 , [[], {Dot , Meta2 , Args }]}]},
@@ -166,12 +175,12 @@ args_from_arity(_Meta, A, _E) when is_integer(A), A >= 0, A =< 255 ->
166175args_from_arity (Meta , A , E ) ->
167176 file_error (Meta , E , ? MODULE , {invalid_arity_for_capture , A }).
168177
169- is_sequential_and_not_empty ([]) -> false ;
170- is_sequential_and_not_empty (List ) -> is_sequential (List , 1 ).
178+ check_sequential_and_not_empty ([]) -> non_sequential ;
179+ check_sequential_and_not_empty (List ) -> check_sequential (List , 1 ).
171180
172- is_sequential ([{'&' , _ , [Int ]} | T ], Int ) -> is_sequential (T , Int + 1 );
173- is_sequential ([], _Int ) -> true ;
174- is_sequential (_ , _Int ) -> false .
181+ check_sequential ([{'&' , _ , [Int ]} | T ], Int ) -> check_sequential (T , Int + 1 );
182+ check_sequential ([], _Int ) -> sequential ;
183+ check_sequential (_ , _Int ) -> non_sequential .
175184
176185handle_capture_possible_warning (Meta , DotMeta , Mod , Fun , Arity , E ) ->
177186 case (Arity =:= 0 ) andalso (lists :keyfind (no_parens , 1 , DotMeta ) /= {no_parens , true }) of
@@ -186,6 +195,10 @@ format_error({parens_remote_capture, Mod, Fun}) ->
186195 io_lib :format (" extra parentheses on a remote function capture &~ts .~ts ()/0 have been "
187196 " deprecated. Please remove the parentheses: &~ts .~ts /0" ,
188197 ['Elixir.Macro' :to_string (Mod ), Fun , 'Elixir.Macro' :to_string (Mod ), Fun ]);
198+ format_error ({complex_module_capture , Mod }) ->
199+ io_lib :format (" expected the module in &module.fun/arity to expand to a variable or an atom, got: ~ts \n "
200+ " You can either compute the module name outside of & or convert it to a regular anonymous function." ,
201+ ['Elixir.Macro' :to_string (Mod )]);
189202format_error (clauses_with_different_arities ) ->
190203 " cannot mix clauses with different arities in anonymous functions" ;
191204format_error (defaults_in_args ) ->
0 commit comments