@@ -15,21 +15,29 @@ expand_map(Meta, Args, S, E) ->
1515 {{'%{}' , Meta , EArgs }, SE , EE }.
1616
1717expand_struct (Meta , Left , {'%{}' , MapMeta , MapArgs }, S , #{context := Context } = E ) ->
18- CleanMapArgs = clean_struct_key_from_map_args (Meta , MapArgs , E ),
18+ CleanMapArgs = delete_struct_key (Meta , MapArgs , E ),
1919 {[ELeft , ERight ], SE , EE } = elixir_expand :expand_args ([Left , {'%{}' , MapMeta , CleanMapArgs }], S , E ),
2020
2121 case validate_struct (ELeft , Context ) of
2222 true when is_atom (ELeft ) ->
23- case extract_struct_assocs (Meta , ERight , E ) of
24- {expand , MapMeta , Assocs } when Context /= match -> % % Expand
23+ case ERight of
24+ {'%{}' , MapMeta , [{'|' , _ , [_ , Assocs ]}]} ->
25+ % % The update syntax for structs is deprecated,
26+ % % so we return only the update syntax downstream.
27+ % % TODO: Remove me on Elixir v2.0
28+ file_warn (MapMeta , ? key (E , file ), ? MODULE , {deprecated_update , ELeft , ERight }),
29+ _ = load_struct_info (Meta , ELeft , Assocs , EE ),
30+ {{'%' , Meta , [ELeft , ERight ]}, SE , EE };
31+
32+ {'%{}' , MapMeta , Assocs } when Context /= match ->
2533 AssocKeys = [K || {K , _ } <- Assocs ],
2634 Struct = load_struct (Meta , ELeft , Assocs , EE ),
2735 Keys = ['__struct__' ] ++ AssocKeys ,
2836 WithoutKeys = lists :sort (maps :to_list (maps :without (Keys , Struct ))),
2937 StructAssocs = elixir_quote :escape (WithoutKeys , none , false ),
3038 {{'%' , Meta , [ELeft , {'%{}' , MapMeta , StructAssocs ++ Assocs }]}, SE , EE };
3139
32- {_ , _ , Assocs } -> % % Update or match
40+ {'%{}' , MapMeta , Assocs } ->
3341 _ = load_struct_info (Meta , ELeft , Assocs , EE ),
3442 {{'%' , Meta , [ELeft , ERight ]}, SE , EE }
3543 end ;
@@ -46,12 +54,12 @@ expand_struct(Meta, Left, {'%{}', MapMeta, MapArgs}, S, #{context := Context} =
4654expand_struct (Meta , _Left , Right , _S , E ) ->
4755 file_error (Meta , E , ? MODULE , {non_map_after_struct , Right }).
4856
49- clean_struct_key_from_map_args (Meta , [{'|' , PipeMeta , [Left , MapAssocs ]}], E ) ->
50- [{'|' , PipeMeta , [Left , clean_struct_key_from_map_assocs (Meta , MapAssocs , E )]}];
51- clean_struct_key_from_map_args (Meta , MapAssocs , E ) ->
52- clean_struct_key_from_map_assocs (Meta , MapAssocs , E ).
57+ delete_struct_key (Meta , [{'|' , PipeMeta , [Left , MapAssocs ]}], E ) ->
58+ [{'|' , PipeMeta , [Left , delete_struct_key_assoc (Meta , MapAssocs , E )]}];
59+ delete_struct_key (Meta , MapAssocs , E ) ->
60+ delete_struct_key_assoc (Meta , MapAssocs , E ).
5361
54- clean_struct_key_from_map_assocs (Meta , Assocs , E ) ->
62+ delete_struct_key_assoc (Meta , Assocs , E ) ->
5563 case lists :keytake ('__struct__' , 1 , Assocs ) of
5664 {value , _ , CleanAssocs } ->
5765 file_warn (Meta , ? key (E , file ), ? MODULE , ignored_struct_key_in_struct ),
@@ -110,16 +118,6 @@ validate_kv(Meta, KV, Original, #{context := Context} = E) ->
110118 file_error (Meta , E , ? MODULE , {not_kv_pair , lists :nth (Index , Original )})
111119 end , {1 , #{}}, KV ).
112120
113- extract_struct_assocs (_ , {'%{}' , Meta , [{'|' , _ , [_ , Assocs ]}]}, _ ) ->
114- {update , Meta , delete_struct_key (Assocs )};
115- extract_struct_assocs (_ , {'%{}' , Meta , Assocs }, _ ) ->
116- {expand , Meta , delete_struct_key (Assocs )};
117- extract_struct_assocs (Meta , Other , E ) ->
118- file_error (Meta , E , ? MODULE , {non_map_after_struct , Other }).
119-
120- delete_struct_key (Assocs ) ->
121- lists :keydelete ('__struct__' , 1 , Assocs ).
122-
123121validate_struct ({'^' , _ , [{Var , _ , Ctx }]}, match ) when is_atom (Var ), is_atom (Ctx ) -> true ;
124122validate_struct ({Var , _Meta , Ctx }, match ) when is_atom (Var ), is_atom (Ctx ) -> true ;
125123validate_struct (Atom , _ ) when is_atom (Atom ) -> true ;
@@ -301,4 +299,9 @@ format_error({invalid_key_for_struct, Key}) ->
301299 io_lib :format (" invalid key ~ts for struct, struct keys must be atoms, got: " ,
302300 ['Elixir.Macro' :to_string (Key )]);
303301format_error (ignored_struct_key_in_struct ) ->
304- " key :__struct__ is ignored when using structs" .
302+ " key :__struct__ is ignored when using structs" ;
303+ format_error ({deprecated_update , Struct , MapUpdate }) ->
304+ io_lib :format (" the struct update syntax is deprecated:\n\n ~ts \n\n "
305+ " Instead, prefer to pattern matching on structs when the variable is first defined and "
306+ " use the regular map update syntax instead:\n\n ~ts \n " ,
307+ ['Elixir.Macro' :to_string ({'%' , [], [Struct , MapUpdate ]}), 'Elixir.Macro' :to_string (MapUpdate )]).
0 commit comments