File 4071-Fix-partial-record-matching-in-map-generator.patch of Package erlang

From 3de9ae0249c7b2fad510e3c3941431d68cd7c9fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Fri, 17 Nov 2023 08:56:36 +0100
Subject: [PATCH] Fix partial record matching in map generator

When attempting to match part of a record in the key of a map
generator, the entire record would be matched.

Example:

    -module(t).
    -export([test/0]).
    -record(r, {a,b}).

    f(Map) ->
        [V || #r{a=N} := V <- Map, is_integer(N)].

    test() ->
        f(#{#r{a=1} => 1, #r{a=2,b=42} => 2}).

It would be expected that `t:test()` would return `[1,2]`, but it
returned `[1]` because the entire record was matched, instead of just
field `a`. Therefore, only the first record `#r{a=1,b=undefined}`
would match.

Fixes #7875
---
 lib/compiler/test/mc_SUITE.erl        | 16 ++++++++++++++++
 lib/stdlib/src/erl_expand_records.erl |  9 ++++++---
 2 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/lib/compiler/test/mc_SUITE.erl b/lib/compiler/test/mc_SUITE.erl
index 9da2b44479..9f26282557 100644
--- a/lib/compiler/test/mc_SUITE.erl
+++ b/lib/compiler/test/mc_SUITE.erl
@@ -55,6 +55,8 @@ init_per_group(_GroupName, Config) ->
 end_per_group(_GroupName, Config) ->
     Config.
 
+-record(foo, {a,b}).
+
 basic(_Config) ->
     mc_double(0),
     mc_double(1),
@@ -106,6 +108,20 @@ basic(_Config) ->
     <<>> = << <<0>> || a := b <- #{x => y} >>,
     <<0>> = << <<0>> || a := b <- #{a => b} >>,
 
+    %% Matching partial records.
+    RecordMap = id(#{#foo{a=I,b=I*I} => I*I*I || I <- [1,2,3,4]}),
+
+    EvenMap = maps:from_list([{K,V} ||
+                                 {#foo{a=N}=K,V} <- maps:to_list(RecordMap),
+                                 N rem 2 =:= 0]),
+    EvenMap = #{K => V ||
+                  #foo{a=N}=K := V <- RecordMap,
+                  N rem 2 =:= 0},
+
+    Odd = lists:sort([V || {#foo{a=N}, V} <- maps:to_list(RecordMap),
+                           N rem 2 =:= 1]),
+    Odd = lists:sort([V || #foo{a=N} := V <- RecordMap, N rem 2 =:= 1]),
+
     ok.
 
 mc_double(Size) ->
diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl
index 706b5fec6e..19a81fefc0 100644
--- a/lib/stdlib/src/erl_expand_records.erl
+++ b/lib/stdlib/src/erl_expand_records.erl
@@ -526,9 +526,12 @@ lc_tq(Anno, [{b_generate,AnnoG,P0,G0} | Qs0], St0) ->
     {[{b_generate,AnnoG,P1,G1} | Qs1],St3};
 lc_tq(Anno, [{m_generate,AnnoG,P0,G0} | Qs0], St0) ->
     {G1,St1} = expr(G0, St0),
-    {P1,St2} = pattern(P0, St1),
-    {Qs1,St3} = lc_tq(Anno, Qs0, St2),
-    {[{m_generate,AnnoG,P1,G1} | Qs1],St3};
+    {map_field_exact,AnnoMFE,KeyP0,ValP0} = P0,
+    {KeyP1,St2} = pattern(KeyP0, St1),
+    {ValP1,St3} = pattern(ValP0, St2),
+    {Qs1,St4} = lc_tq(Anno, Qs0, St3),
+    P1 = {map_field_exact,AnnoMFE,KeyP1,ValP1},
+    {[{m_generate,AnnoG,P1,G1} | Qs1],St4};
 lc_tq(Anno, [F0 | Qs0], #exprec{calltype=Calltype,raw_records=Records}=St0) ->
     %% Allow record/2 and expand out as guard test.
     IsOverriden = fun(FA) ->
-- 
2.35.3

openSUSE Build Service is sponsored by