aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2012-08-20 10:11:38 +0200
committerBjörn Gustavsson <[email protected]>2012-10-09 15:24:38 +0200
commit562cf135b9518985d172d291665eb32f891032fb (patch)
treeb2bd122624ba23a6dae83a379ad652e59efea94e /lib
parentb68297d347a9a041854410a77861982b1d0861d2 (diff)
downloadotp-562cf135b9518985d172d291665eb32f891032fb.tar.gz
otp-562cf135b9518985d172d291665eb32f891032fb.tar.bz2
otp-562cf135b9518985d172d291665eb32f891032fb.zip
v3_kernel: Fix match code for matched out segment size in multiple clauses
When matched variable is used as a size field in multiple clauses, as in: foo(<<L:8,A:L>>) -> A; foo(<<L:8,A:L,B:8>>) -> {A,B}. the match tree would branch out before the segment that used the matched-out variable (in this example, the tree would branch out before the matching of A:L). That happens because the pattern matching compilator did not take variable substitutions into account when grouping clauses that match the same value. That is, the generated code would work similarly to this code: foo(<<L:8,T/binary>>) -> case T of <<A:L>> -> A; _ -> case T of <<A:L,B:8>> -> %% A matched out again! {A,B} end end. We would like the matching to work more like: foo(<<L,A:L,T/binary>>) -> case T of <<>> -> A; <<B:8>> -> {A,B} end. Fix the problem by taking the substitutions into account when grouping clauses that match out the same value.
Diffstat (limited to 'lib')
-rw-r--r--lib/compiler/src/v3_kernel.erl12
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl31
2 files changed, 38 insertions, 5 deletions
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index b69ad416db..8ef71e1346 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -1381,7 +1381,7 @@ clause_arg(#iclause{pats=[Arg|_]}) -> Arg.
clause_con(C) -> arg_con(clause_arg(C)).
-clause_val(C) -> arg_val(clause_arg(C)).
+clause_val(C) -> arg_val(clause_arg(C), C).
is_var_clause(C) -> clause_con(C) =:= k_var.
@@ -1412,7 +1412,7 @@ arg_con(Arg) ->
#k_var{} -> k_var
end.
-arg_val(Arg) ->
+arg_val(Arg, C) ->
case arg_arg(Arg) of
#k_literal{val=Lit} -> Lit;
#k_int{val=I} -> I;
@@ -1420,7 +1420,13 @@ arg_val(Arg) ->
#k_atom{val=A} -> A;
#k_tuple{es=Es} -> length(Es);
#k_bin_seg{size=S,unit=U,type=T,flags=Fs} ->
- {set_kanno(S, []),U,T,Fs}
+ case S of
+ #k_var{name=V} ->
+ #iclause{isub=Isub} = C,
+ {#k_var{name=get_vsub(V, Isub)},U,T,Fs};
+ _ ->
+ {set_kanno(S, []),U,T,Fs}
+ end
end.
%% ubody_used_vars(Expr, State) -> [UsedVar]
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 01b7568122..0e9d0bbc17 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -33,7 +33,7 @@
matching_meets_construction/1,simon/1,matching_and_andalso/1,
otp_7188/1,otp_7233/1,otp_7240/1,otp_7498/1,
match_string/1,zero_width/1,bad_size/1,haystack/1,
- cover_beam_bool/1]).
+ cover_beam_bool/1,matched_out_size/1]).
-export([coverage_id/1,coverage_external_ignore/2]).
@@ -53,7 +53,7 @@ all() ->
matching_meets_construction, simon,
matching_and_andalso, otp_7188, otp_7233, otp_7240,
otp_7498, match_string, zero_width, bad_size, haystack,
- cover_beam_bool].
+ cover_beam_bool, matched_out_size].
groups() ->
[].
@@ -1062,6 +1062,33 @@ do_cover_beam_bool(Bin, X) when X > 0 ->
do_cover_beam_bool(<<_,Bin/binary>>, X) ->
do_cover_beam_bool(Bin, X+1).
+matched_out_size(Config) when is_list(Config) ->
+ {253,16#DEADBEEF} = mos_int(<<8,253,16#DEADBEEF:32>>),
+ {6,16#BEEFDEAD} = mos_int(<<3,6:3,16#BEEFDEAD:32>>),
+ {53,16#CAFEDEADBEEFCAFE} = mos_int(<<16,53:16,16#CAFEDEADBEEFCAFE:64>>),
+ {23,16#CAFEDEADBEEFCAFE} = mos_int(<<5,23:5,16#CAFEDEADBEEFCAFE:64>>),
+
+ {<<1,2,3>>,4} = mos_bin(<<3,1,2,3,4,3>>),
+ {<<1,2,3,7>>,19,42} = mos_bin(<<4,1,2,3,7,19,4,42>>),
+ <<1,2,3,7>> = mos_bin(<<4,1,2,3,7,"abcdefghij">>),
+
+ ok.
+
+mos_int(<<L,I:L,X:32>>) ->
+ {I,X};
+mos_int(<<L,I:L,X:64>>) ->
+ {I,X}.
+
+mos_bin(<<L,Bin:L/binary,X:8,L>>) ->
+ L = byte_size(Bin),
+ {Bin,X};
+mos_bin(<<L,Bin:L/binary,X:8,L,Y:8>>) ->
+ L = byte_size(Bin),
+ {Bin,X,Y};
+mos_bin(<<L,Bin:L/binary,"abcdefghij">>) ->
+ L = byte_size(Bin),
+ Bin.
+
check(F, R) ->
R = F().