File 0210-compiler-Disallow-multiple-_-as-record-field-key.patch of Package erlang
From 42a8fee1e4f4c7545a2d34c5b2bc4df1fde3bf59 Mon Sep 17 00:00:00 2001
From: Hans Bolinder <hasse@erlang.org>
Date: Mon, 2 Mar 2020 15:19:11 +0100
Subject: [PATCH 2/2] compiler: Disallow multiple '_' as record field key
There is no way to fix:
-record(r, {f, g}).
f(#r{_ = V1, _ = V2, f = 17}) -> {V1, V2}.
Compilation with 'E' showed why:
f({r, 17, V1}) ->
{V1, V2}.
This case is similar to the last commit, "Disallow '_' as record field
key without effect", as the second initialization has no effect.
---
lib/stdlib/src/erl_lint.erl | 7 +++--
lib/stdlib/test/erl_lint_SUITE.erl | 52 ++++++++++++++++++++++++++++++++++++++
2 files changed, 57 insertions(+), 2 deletions(-)
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 7b86015594..fee0a1bf05 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -2752,9 +2752,12 @@ check_field({record_field,Lf,{atom,La,F},Val}, Name, Fields,
error -> {[],add_error(La, {undefined_field,Name,F}, St)}
end}
end;
-check_field({record_field,_Lf,{var,_La,'_'},Val}, _Name, _Fields,
+check_field({record_field,_Lf,{var,La,'_'=F},Val}, _Name, _Fields,
Vt, St, Sfs, CheckFun) ->
- {Sfs,CheckFun(Val, Vt, St)};
+ case member(F, Sfs) of
+ true -> {Sfs,{[],add_error(La, bad_multi_field_init, St)}};
+ false -> {[F|Sfs],CheckFun(Val, Vt, St)}
+ end;
check_field({record_field,_Lf,{var,La,V},_Val}, Name, _Fields,
Vt, St, Sfs, _CheckFun) ->
{Sfs,{Vt,add_error(La, {field_name_is_variable,Name,V}, St)}}.
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index 0533aef4d2..92667bf6e5 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -4340,6 +4340,10 @@ removed(Config) when is_list(Config) ->
ok.
otp_16516(Config) when is_list(Config) ->
+ one_multi_init(Config),
+ several_multi_inits(Config).
+
+one_multi_init(Config) ->
"'_' initializes no omitted fields" =
format_error(bad_multi_field_init),
Ts = [{otp_16516_1,
@@ -4380,6 +4384,54 @@ otp_16516(Config) when is_list(Config) ->
[]}],
[] = run(Config, Ts).
+several_multi_inits(Config) ->
+ Ts = [{otp_16516_4,
+ <<"-record(r, {f, g}).
+ t(#r{f = 17, _ = V1,
+ _ = V2}) ->
+ {V1, V2}.
+ u(#r{_ = V1, f = 17,
+ _ = V2}) ->
+ {V1, V2}.
+ v(#r{_ = V1, f = 17}) ->
+ V1.
+ ">>,
+ [],
+ {errors,[{3,erl_lint,bad_multi_field_init},
+ {4,erl_lint,{unbound_var,'V1'}},
+ {4,erl_lint,{unbound_var,'V2'}},
+ {6,erl_lint,bad_multi_field_init},
+ {7,erl_lint,{unbound_var,'V1'}},
+ {7,erl_lint,{unbound_var,'V2'}}],[]}},
+ {otp_16516_5,
+ <<"-record(r, {f, g}).
+ t(V1, V2) ->
+ #r{_ = V1, f = 3,
+ _ = V2}.
+ u(V1, V2) ->
+ #r{_ = V1,
+ _ = V2, f = 3}.
+ ">>,
+ [],
+ {error,[{4,erl_lint,bad_multi_field_init},
+ {7,erl_lint,bad_multi_field_init}],
+ [{2,erl_lint,{unused_var,'V2'}},{5,erl_lint,{unused_var,'V2'}}]}},
+ {otp_16516_6,
+ <<"-record(r, {f, g}).
+ t(V1, V2) when #r{_ = V1, f = 3,
+ _ = V2} =:= #r{} ->
+ a.
+ u(V1, V2) when #r{_ = V1, f = 3,
+ _ = V2} =:= #r{} ->
+ a.
+ ">>,
+ [],
+ {error,[{3,erl_lint,bad_multi_field_init},
+ {6,erl_lint,bad_multi_field_init}],
+ [{2,erl_lint,{unused_var,'V2'}},
+ {5,erl_lint,{unused_var,'V2'}}]}}],
+ [] = run(Config, Ts).
+
format_error(E) ->
lists:flatten(erl_lint:format_error(E)).
--
2.16.4