@@ -38,13 +38,75 @@ defmodule Kernel.RecordRewriter do
3838 optimize_body ( t , new_dict , [ new_expr | acc ] )
3939 end
4040
41+ ## Record helpers
42+
43+ defp record_fields ( record ) do
44+ if Code . ensure_loaded? ( record ) && function_exported? ( record , :__record__ , 1 ) do
45+ try do
46+ fields = lc { k , _ } in list record . __record__ ( :fields ) , do: k
47+ optimizable = record . __record__ ( :optimizable )
48+ { fields , optimizable }
49+ rescue
50+ [ UndefinedFunctionError , FunctionClauseError ] -> { [ ] , [ ] }
51+ end
52+ end
53+ end
54+
55+ defp record_field_info ( function ) do
56+ case atom_to_list ( function ) do
57+ 'update_' ++ field -> { :update , list_to_atom ( function ) }
58+ _ -> { :accessor , function }
59+ end
60+ end
61+
62+ defp optimize_call ( line , { record , _ } = res , left , { :atom , _ , function } , args ) do
63+ { fields , optimizable } = record_fields ( record )
64+
65+ if List . member? ( optimizable , { function , length ( args ) + 1 } ) do
66+ { kind , field } = record_field_info ( function )
67+ if index = Enum . find_index ( fields , field == & 1 ) do
68+ optimize_call ( line , res , kind , index , left , args )
69+ end
70+ end
71+ end
72+
73+ defp optimize_call ( _line , _res , _left , _right , _args ) do
74+ nil
75+ end
76+
77+ defp optimize_call ( line , _res , :accessor , index , left , [ ] ) do
78+ call = { :call , line ,
79+ { :remote , line , { :atom , 0 , :erlang } , { :atom , 0 , :element } } ,
80+ [ { :integer , 0 , index + 2 } , left ]
81+ }
82+ { call , nil }
83+ end
84+
85+ defp optimize_call ( line , res , :accessor , index , left , [ arg ] ) do
86+ call = { :call , line ,
87+ { :remote , line , { :atom , 0 , :erlang } , { :atom , 0 , :setelement } } ,
88+ [ { :integer , 0 , index + 2 } , left , arg ]
89+ }
90+ { call , res }
91+ end
92+
93+ defp optimize_call ( _line , _res , :update , _index , _left , [ _arg ] ) do
94+ nil
95+ end
96+
4197 ## Expr
4298
4399 defp optimize_expr ( { :call , call_line , { :remote , line , left , right } , args } , dict ) do
44- { left , dict , _ } = optimize_expr ( left , dict )
100+ { left , dict , res } = optimize_expr ( left , dict )
45101 { right , dict , _ } = optimize_expr ( right , dict )
46102 { args , dict } = optimize_args ( args , dict )
47- { { :call , call_line , { :remote , line , left , right } , args } , dict , nil }
103+
104+ case optimize_call ( call_line , res , left , right , args ) do
105+ { call , call_res } ->
106+ { call , dict , call_res }
107+ nil ->
108+ { { :call , call_line , { :remote , line , left , right } , args } , dict , nil }
109+ end
48110 end
49111
50112 defp optimize_expr ( { :call , line , expr , args } , dict ) do
@@ -212,21 +274,19 @@ defmodule Kernel.RecordRewriter do
212274 end
213275
214276 defp assign_vars ( [ key | t ] , dict , { value , _ } = res ) when is_atom ( key ) and value != nil do
215- if is_record? ( value ) do
216- dict =
217- case :orddict . find ( key , dict ) do
218- { :ok , ^ res } ->
219- dict
220- { :ok , { ^ value , _ } } ->
221- :orddict . store ( key , { value , nil } , dict )
222- { :ok , _ } ->
223- # We are overriding a type of an existing variable,
224- # which means the source code is invalid.
225- :orddict . store ( key , nil , dict )
226- :error ->
227- :orddict . store ( key , res , dict )
228- end
229- end
277+ dict =
278+ case :orddict . find ( key , dict ) do
279+ { :ok , ^ res } ->
280+ dict
281+ { :ok , { ^ value , _ } } ->
282+ :orddict . store ( key , { value , nil } , dict )
283+ { :ok , _ } ->
284+ # We are overriding a type of an existing variable,
285+ # which means the source code is invalid.
286+ :orddict . store ( key , nil , dict )
287+ :error ->
288+ :orddict . store ( key , res , dict )
289+ end
230290
231291 assign_vars t , dict , res
232292 end
@@ -305,11 +365,4 @@ defmodule Kernel.RecordRewriter do
305365 defp join_result ( [ ] , res ) do
306366 res
307367 end
308-
309- ## Record helpers
310-
311- # TODO: Implement proper record check
312- defp is_record? ( _h ) do
313- true
314- end
315368end
0 commit comments