From 20b85926d633d5c77f1e5f10bab5c909c9220a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 2 Oct 2024 07:01:03 +0200 Subject: [PATCH] fixup! compiler: Add zip generators for comprehensions --- lib/compiler/src/v3_core.erl | 67 +++++++++++++++++---------------- lib/compiler/test/zlc_SUITE.erl | 49 +++++++++++++++++++++--- 2 files changed, 78 insertions(+), 38 deletions(-) diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index 533ee2bff86..0d682bd9bc4 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -1662,46 +1662,47 @@ zip_tq(Line, E, #izip{arg=[#igen{anno=#a{anno=GA}=GAnno, %% Generate the clauses for the letrec. AccPats = collect_for_zip(accpats, Generators), - {Cs, St} = - case member(nomatch, AccPats) of - true -> - %% At least one generator will never match. - {[], St3}; + + TailVars = collect_for_zip(tails, Generators), + Nc = #iapply{anno=GAnno,op=F,args=TailVars}, + {Lc,Lps,St4} = lc_tq(Line, E, Qs, Nc, St3), + + AccClause = case member(nomatch, AccPats) of + true -> + nomatch; + false -> + make_clause(LA, AccPats, AccGuard, Lps++[Lc]) + end, + + TailPats = collect_for_zip(tailpats, Generators), + TailClause = make_clause(LA, TailPats, [], [Mc]), + + SkipPats = collect_for_zip(skip_pats, Generators), + SkipClause = make_clause(LA, SkipPats, [], [Nc]), + + RefillPats0 = collect_for_zip(refillpats, Generators), + RefillClause = + case all(fun(X) -> X =:= nomatch end, RefillPats0) of + true -> + %% There are no map generators. + nomatch; false -> - TailVars = collect_for_zip(tails, Generators), - Nc = #iapply{anno=GAnno,op=F,args=TailVars}, - {Lc,Lps,St4} = lc_tq(Line, E, Qs, Nc, St3), - - AccClause = make_clause(LA, AccPats, AccGuard, Lps++[Lc]), - - TailPats = collect_for_zip(tailpats, Generators), - TailClause = make_clause(LA, TailPats, [], [Mc]), - - RefillPats0 = collect_for_zip(refillpats, Generators), - RefillClause = - case all(fun(X) -> X =:= nomatch end, RefillPats0) of - true -> - %% There are no map generators. - []; - false -> - RefillPats = make_ignored(RefillPats0, TailVars), - RefillAs = collect_for_zip(refillas, Generators), - RefillBody = [C || C <- RefillAs, C =/= ignore], - [make_clause(LA, RefillPats, [], RefillBody++[Nc])] - end, - - Cs0 = [AccClause, TailClause | RefillClause], - Cs1 = [C || C <- Cs0, C =/= nomatch], - {Cs1, St4} + RefillPats = make_ignored(RefillPats0, TailVars), + RefillAs = collect_for_zip(refillas, Generators), + RefillBody = [C || C <- RefillAs, C =/= ignore], + make_clause(LA, RefillPats, [], RefillBody++[Nc]) end, + Cs0 = [AccClause, TailClause, SkipClause, RefillClause], + Cs = [C || C <- Cs0, C =/= nomatch], + Fc = bad_generators(FcVars, Arg, lc), Fun = #ifun{anno=GAnno,id=[],vars=CallVars,clauses=Cs,fc=Fc}, {#iletrec{anno=GAnno#a{anno=[list_comprehension|GA]}, defs=[{{Name,NumGenerators},Fun}], body=append(collect_for_zip(pres, Generators)) ++ [#iapply{anno=GAnno,op=F,args=collect_for_zip(args, Generators)}]}, - [],St}. + [],St4}. %% bc_tq(Line, Exp, [Qualifier], More, State) -> {LetRec,[PreExp],State}. %% This TQ from Gustafsson ERLANG'05. @@ -1891,7 +1892,9 @@ collect_for_zip(What, Qs) -> refillas -> fun(#igen{refill={_, R}}) -> R end; pres -> - fun(#igen{arg={Pre, _}}) -> Pre end + fun(#igen{arg={Pre, _}}) -> Pre end; + skip_pats -> + fun(#igen{skip_pat=SkipPat}) -> SkipPat end end, [F(Q) || #igen{} = Q <- Qs]. diff --git a/lib/compiler/test/zlc_SUITE.erl b/lib/compiler/test/zlc_SUITE.erl index 5ab07ef5118..f5e80367538 100644 --- a/lib/compiler/test/zlc_SUITE.erl +++ b/lib/compiler/test/zlc_SUITE.erl @@ -74,6 +74,7 @@ basic(Config) when is_list(Config) -> mixed_zlc(), zmc(), filter_guard(), + filter_pattern(), cartesian(), nomatch(), bad_generators(). @@ -146,6 +147,27 @@ filter_guard() -> #{c := 3} = #{X => Y || X <- [a,b,c] && Y <- [1,2,3], Y rem 2 == 1, Y > 1}, #{c := 3,a := 1} = #{X => Y || X <- [a,b,c] && <> <= <<1,2,3>>, Y rem 2 == 1}. +filter_pattern() -> + [] = do_filter_pat_1([], []), + [] = do_filter_pat_1([a], [a]), + [] = do_filter_pat_1([{ok,a}], [{error,e}]), + + + [] = do_filter_pat_2([], []), + [] = do_filter_pat_2([a], [b]), + [] = do_filter_pat_2([{a,1}], [{b,1}]), + [{1,7}] = do_filter_pat_2([{a,1}], [{a,7}]), + [{1,7},{10,20}] = do_filter_pat_2([{a,1},{b,9},{x,10}], + [{a,7},{wrong,8},{x,20}]), + + ok. + +do_filter_pat_1(L1, L2) -> + [{A,B} || {ok,A} <- L1 && {ok,B} <- L2]. + +do_filter_pat_2(L1, L2) -> + [{A,B} || {Same,A} <- L1 && {Same,B} <- L2]. + cartesian() -> [{a, 3}, {b, 5}, {c, 7}, {a, 4}, {b, 6}, {c, 8}] = [{X, W+Y} || W <- [1,2], X <- [a, b, c] && <> <= <<2, 4, 6>>], @@ -159,13 +181,23 @@ cartesian() -> ok. nomatch() -> - {'EXIT',{{bad_generators,{[a,b],[c]}},_}} = (catch [{X, Y} || a=b=X <- [a,b] && - Y <- [c]]), - {'EXIT',{{bad_generators,{[1,2],<<3>>}},_}} = (catch - << <<(X+Y)/integer>> || a=b=X <- [1,2] && - <> <= <<3>> >>). + [] = do_nomatch_1([], []), + [] = do_nomatch_1([1], [a]), + [] = do_nomatch_1([1,2], [a,b]), + {'EXIT',{{bad_generators,{[1,2,3],[]}},_}} = do_nomatch_1([1,2,3], []), + {'EXIT',{{bad_generators,{[3],[]}},_}} = do_nomatch_1([1,2,3], [a,b]), -id(I) -> I. + %% <<>> = do_nomatch_2([], <<>>), + %% <<>> = do_nomatch_2([a], <<1>>), + {'EXIT',{{bad_generators,{[1,2],<<3>>}},_}} = do_nomatch_2([1,2], <<3>>), + + ok. + +do_nomatch_1(L1, L2) -> + catch [{X, Y} || a=b=X <- L1 && Y <- L2]. + +do_nomatch_2(L, Bin) -> + catch << <<(X+Y)/integer>> || a=b=X <- L && <> <= Bin >>. bad_generators() -> @@ -214,6 +246,11 @@ bad_generators() -> end, ok. +%%% Common utilities. + +id(I) -> I. + + -file("bad_zlc.erl", 1). bad_generators(L1,L2) -> %Line 2 [{I1, I2} || %Line 3