805
%%% Replace is_record/3 in guards with matching if possible.
808
optimize_is_record(H0, G0, #exprec{compile=Opts}) ->
809
case opt_rec_vars(G0) of
813
case lists:member(no_is_record_optimization, Opts) of
817
{H,Rs} = opt_pattern_list(H0, Rs0),
818
G = opt_remove(G0, Rs),
824
%% opt_rec_vars(Guards) -> Vars.
825
%% Search through the guard expression, looking for
826
%% variables referenced in those is_record/3 calls that
827
%% will fail the entire guard if they evaluate to 'false'
829
%% In the following code
831
%% f(X, Y, Z) when is_record(X, r1) andalso
832
%% (is_record(Y, r2) orelse is_record(Z, r3))
834
%% the entire guard will be false if the record test for
835
%% X fails, and the clause can be rewritten to:
837
%% f({r1,...}=X, Y, Z) when true andalso
838
%% (is_record(Y, r2) or is_record(Z, r3))
840
opt_rec_vars([G|Gs]) ->
841
Rs = opt_rec_vars_1(G, orddict:new()),
842
opt_rec_vars(Gs, Rs);
843
opt_rec_vars([]) -> orddict:new().
845
opt_rec_vars([G|Gs], Rs0) ->
846
Rs1 = opt_rec_vars_1(G, orddict:new()),
847
Rs = ordsets:intersection(Rs0, Rs1),
848
opt_rec_vars(Gs, Rs);
849
opt_rec_vars([], Rs) -> Rs.
851
opt_rec_vars_1([T|Ts], Rs0) ->
852
Rs = opt_rec_vars_2(T, Rs0),
853
opt_rec_vars_1(Ts, Rs);
854
opt_rec_vars_1([], Rs) -> Rs.
856
opt_rec_vars_2({op,_,'and',A1,A2}, Rs) ->
857
opt_rec_vars_1([A1,A2], Rs);
858
opt_rec_vars_2({op,_,'andalso',A1,A2}, Rs) ->
859
opt_rec_vars_1([A1,A2], Rs);
860
opt_rec_vars_2({op,_,'orelse',Arg,{atom,_,fail}}, Rs) ->
861
%% Since the second argument guarantees failure,
862
%% it is safe to inspect the first argument.
863
opt_rec_vars_2(Arg, Rs);
864
opt_rec_vars_2({call,_,{remote,_,{atom,_,erlang},{atom,_,is_record}},
865
[{var,_,V},{atom,_,Tag},{integer,_,Sz}]}, Rs) ->
866
orddict:store(V, {Tag,Sz}, Rs);
867
opt_rec_vars_2({call,_,{atom,_,is_record},
868
[{var,_,V},{atom,_,Tag},{integer,_,Sz}]}, Rs) ->
869
orddict:store(V, {Tag,Sz}, Rs);
870
opt_rec_vars_2(_, Rs) -> Rs.
872
opt_pattern_list(Ps, Rs) ->
873
opt_pattern_list(Ps, Rs, []).
875
opt_pattern_list([P0|Ps], Rs0, Acc) ->
876
{P,Rs} = opt_pattern(P0, Rs0),
877
opt_pattern_list(Ps, Rs, [P|Acc]);
878
opt_pattern_list([], Rs, Acc) ->
881
opt_pattern({var,_,V}=Var, Rs0) ->
882
case orddict:find(V, Rs0) of
884
Rs = orddict:store(V, {remove,Tag,Sz}, Rs0),
885
{opt_var(Var, Tag, Sz),Rs};
889
opt_pattern({cons,Line,H0,T0}, Rs0) ->
890
{H,Rs1} = opt_pattern(H0, Rs0),
891
{T,Rs} = opt_pattern(T0, Rs1),
892
{{cons,Line,H,T},Rs};
893
opt_pattern({tuple,Line,Es0}, Rs0) ->
894
{Es,Rs} = opt_pattern_list(Es0, Rs0),
895
{{tuple,Line,Es},Rs};
896
opt_pattern({match,Line,Pa0,Pb0}, Rs0) ->
897
{Pa,Rs1} = opt_pattern(Pa0, Rs0),
898
{Pb,Rs} = opt_pattern(Pb0, Rs1),
899
{{match,Line,Pa,Pb},Rs};
900
opt_pattern(P, Rs) -> {P,Rs}.
902
opt_var({var,Line,_}=Var, Tag, Sz) ->
903
Rp = record_pattern(2, -1, ignore, Sz, Line, [{atom,Line,Tag}]),
904
{match,Line,{tuple,Line,Rp},Var}.
906
opt_remove(Gs, Rs) ->
907
[opt_remove_1(G, Rs) || G <- Gs].
909
opt_remove_1(Ts, Rs) ->
910
[opt_remove_2(T, Rs) || T <- Ts].
912
opt_remove_2({op,L,'and'=Op,A1,A2}, Rs) ->
913
{op,L,Op,opt_remove_2(A1, Rs),opt_remove_2(A2, Rs)};
914
opt_remove_2({op,L,'andalso'=Op,A1,A2}, Rs) ->
915
{op,L,Op,opt_remove_2(A1, Rs),opt_remove_2(A2, Rs)};
916
opt_remove_2({op,L,'orelse',A1,A2}, Rs) ->
917
{op,L,'orelse',opt_remove_2(A1, Rs),A2};
918
opt_remove_2({call,Line,{remote,_,{atom,_,erlang},{atom,_,is_record}},
919
[{var,_,V},{atom,_,Tag},{integer,_,Sz}]}=A, Rs) ->
920
case orddict:find(V, Rs) of
921
{ok,{remove,Tag,Sz}} ->
926
opt_remove_2({call,Line,{atom,_,is_record},
927
[{var,_,V},{atom,_,Tag},{integer,_,Sz}]}=A, Rs) ->
928
case orddict:find(V, Rs) of
929
{ok,{remove,Tag,Sz}} ->
934
opt_remove_2(A, _) -> A.
808
937
erl_parse:set_line(L, fun(Line) -> -abs(Line) end).