diff options
author | Björn Gustavsson <[email protected]> | 2015-01-15 17:17:11 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2015-01-26 13:08:11 +0100 |
commit | a1243173ed98d1006914337b94f28c9594bd8b02 (patch) | |
tree | 210c6efaaedc38ad7b91efa04a7db0e8ea7baf44 /lib/compiler/src | |
parent | 62c1dd9d9994367da43212f1b33c9e2dacb27e4b (diff) | |
download | otp-a1243173ed98d1006914337b94f28c9594bd8b02.tar.gz otp-a1243173ed98d1006914337b94f28c9594bd8b02.tar.bz2 otp-a1243173ed98d1006914337b94f28c9594bd8b02.zip |
Fix handling of binary map keys in comprehensions
The translation of list comprehension with a map pattern
with a big literal binary as key such as:
lc(L) ->
[V || #{<<2:301>> := V} <- L].
would generate Core Erlang code where an unbound variable
were referenced:
'lc'/1 =
fun (L) ->
letrec
'lc$^0'/1 = fun (_cor4) ->
case _cor4 of
<[~{~<_cor1,V>}~|_cor3]> when 'true' ->
let <_cor5> = apply 'lc$^0'/1(_cor3)
in [V|_cor5]
<[_cor2|_cor3]> when 'true' ->
apply 'lc$^0'/1(_cor3)
<[]> when 'true' ->
[]
end
in let <_cor1> = #{#<2>(301,1,'integer',['unsigned'|['big']])}#
in apply 'lc$^0'/1(L)
In the map pattern in the 'case' in the 'letrec', the key is the
variable '_cor1' which should be bound in the enclosing environment.
It is not.
There is binding of '_cor1', but in the wrong place (at the end of
the function). Because of the way v3_kernel translates letrecs,
the code *happens* to work.
The code will break if Core Erlang optimizations were strengthened
to more aggressively eliminate variable bindings that are not used,
or if the translation from Core Erlang to Kernel Erlang were changed.
Correct the translation so that '_cor1' is bound in the environment
enclosing the 'letrec':
'lc'/1 =
fun (L) ->
let <_cor1> = #{#<2>(301,1,'integer',['unsigned'|['big']])}#
in letrec
'lc$^0'/1 = fun (_cor4) ->
case _cor4 of
<[~{~<_cor1,V>}~|_cor3]> when 'true' ->
let <_cor5> = apply 'lc$^0'/1(_cor3)
in [V|_cor5]
<[_cor2|_cor3]> when 'true' ->
apply 'lc$^0'/1(_cor3)
<[]> when 'true' ->
[]
end
in apply 'lc$^0'/1(L)
Unfortunately I was not able to come up with a test case that
demonstrates the bug.
Diffstat (limited to 'lib/compiler/src')
-rw-r--r-- | lib/compiler/src/v3_core.erl | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index 612660c2d6..b861de3bbb 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -105,7 +105,8 @@ -record(iset, {anno=#a{},var,arg}). -record(itry, {anno=#a{},args,vars,body,evars,handler}). -record(ifilter, {anno=#a{},arg}). --record(igen, {anno=#a{},acc_pat,acc_guard,skip_pat,tail,tail_pat,arg}). +-record(igen, {anno=#a{},ceps=[],acc_pat,acc_guard, + skip_pat,tail,tail_pat,arg}). -type iapply() :: #iapply{}. -type ibinary() :: #ibinary{}. @@ -1011,7 +1012,8 @@ fun_tq({_,_,Name}=Id, Cs0, L, St0, NameInfo) -> %% lc_tq(Line, Exp, [Qualifier], Mc, State) -> {LetRec,[PreExp],State}. %% This TQ from Simon PJ pp 127-138. -lc_tq(Line, E, [#igen{anno=GAnno,acc_pat=AccPat,acc_guard=AccGuard, +lc_tq(Line, E, [#igen{anno=GAnno,ceps=Ceps, + acc_pat=AccPat,acc_guard=AccGuard, skip_pat=SkipPat,tail=Tail,tail_pat=TailPat, arg={Pre,Arg}}|Qs], Mc, St0) -> {Name,St1} = new_fun_name("lc", St0), @@ -1046,7 +1048,7 @@ lc_tq(Line, E, [#igen{anno=GAnno,acc_pat=AccPat,acc_guard=AccGuard, Fun = #ifun{anno=LAnno,id=[],vars=[Var],clauses=Cs,fc=Fc}, {#iletrec{anno=LAnno#a{anno=[list_comprehension|LA]},defs=[{{Name,1},Fun}], body=Pre ++ [#iapply{anno=LAnno,op=F,args=[Arg]}]}, - [],St4}; + Ceps,St4}; lc_tq(Line, E, [#ifilter{}=Filter|Qs], Mc, St) -> filter_tq(Line, E, Filter, Mc, St, Qs, fun lc_tq/5); lc_tq(Line, E0, [], Mc0, St0) -> @@ -1071,7 +1073,8 @@ bc_tq(Line, Exp, Qs0, _, St0) -> args=[Sz]}}] ++ BcPre, {E,Pre,St}. -bc_tq1(Line, E, [#igen{anno=GAnno,acc_pat=AccPat,acc_guard=AccGuard, +bc_tq1(Line, E, [#igen{anno=GAnno,ceps=Ceps, + acc_pat=AccPat,acc_guard=AccGuard, skip_pat=SkipPat,tail=Tail,tail_pat=TailPat, arg={Pre,Arg}}|Qs], Mc, St0) -> {Name,St1} = new_fun_name("lbc", St0), @@ -1109,7 +1112,7 @@ bc_tq1(Line, E, [#igen{anno=GAnno,acc_pat=AccPat,acc_guard=AccGuard, Fun = #ifun{anno=LAnno,id=[],vars=Vars,clauses=Cs,fc=Fc}, {#iletrec{anno=LAnno#a{anno=[list_comprehension|LA]},defs=[{{Name,2},Fun}], body=Pre ++ [#iapply{anno=LAnno,op=F,args=[Arg,Mc]}]}, - [],St4}; + Ceps,St4}; bc_tq1(Line, E, [#ifilter{}=Filter|Qs], Mc, St) -> filter_tq(Line, E, Filter, Mc, St, Qs, fun bc_tq1/5); bc_tq1(_, {bin,Bl,Elements}, [], AccVar, St0) -> @@ -1245,8 +1248,9 @@ generator(Line, {generate,Lg,P0,E}, Gs, St0) -> ann_c_cons(LA, Skip, Tail)} end, {Ce,Pre,St4} = safe(E, St3), - Gen = #igen{anno=#a{anno=GA},acc_pat=AccPat,acc_guard=Cg,skip_pat=SkipPat, - tail=Tail,tail_pat=#c_literal{anno=LA,val=[]},arg={Ceps++Pre,Ce}}, + Gen = #igen{anno=#a{anno=GA},ceps=Ceps, + acc_pat=AccPat,acc_guard=Cg,skip_pat=SkipPat, + tail=Tail,tail_pat=#c_literal{anno=LA,val=[]},arg={Pre,Ce}}, {Gen,St4}; generator(Line, {b_generate,Lg,P,E}, Gs, St0) -> LA = lineno_anno(Line, St0), |