File 1411-Make-typing-of-sets.erl-more-precise.patch of Package erlang

From 53b9799afffbb92f63879c1e0d24e64c0908bdab Mon Sep 17 00:00:00 2001
From: Radek Szymczyszyn <lavrin@gmail.com>
Date: Mon, 9 Mar 2026 16:00:02 +0100
Subject: [PATCH] Make typing of sets.erl more precise

Some functions which are supposed to handle just the version 1 sets use
the public opaque type `set(_)`, which is a union type.

This works with Dialyzer and is explained
in `lib/dialyzer/doc/guides/dialyzer_chapter.md`:

> If the inferred and specified types do not overlap, Dialyzer will warn that the
> spec is invalid with respect to the implementation. However, if they do overlap,
> Dialyzer will proceed under the assumption that the correct type for the given
> function is the intersection of the inferred type and the specified type (the
> rationale being that the user may know something that Dialyzer itself cannot
> deduce).

This eliminates the version 2 type from the specified argument union type,
leaving only the record type.

Silently taking the intersection of a specified type
and inferred type of a function may lead to inaccurate specs lingering in code.
A stricter type checker could prevent that, but then the current
specs in `sets.erl` would lead to a number of false positives.

Giving explicit names to public `set(_)` type members and typing the few relevant
functions only with the version 1 type solves this cleanly.
---
 lib/stdlib/src/sets.erl | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/lib/stdlib/src/sets.erl b/lib/stdlib/src/sets.erl
index 7621a5b008..69bdca3e52 100644
--- a/lib/stdlib/src/sets.erl
+++ b/lib/stdlib/src/sets.erl
@@ -161,7 +161,10 @@ representations.
 
 -type set() :: set(_).
 
--opaque set(Element) :: #set{segs :: segs(Element)} | #{Element => ?VALUE}.
+-opaque set(Element) :: set_v1(Element) | set_v2(Element).
+
+-type set_v1(Element) :: #set{segs :: segs(Element)}.
+-type set_v2(Element) :: #{Element => ?VALUE}.
 
 %%------------------------------------------------------------------------------
 
@@ -465,8 +468,8 @@ del_element(E, #set{}=S0) ->
 %% update_bucket(Set, Slot, NewBucket) -> UpdatedSet.
 %%  Replace bucket in Slot by NewBucket
 -spec update_bucket(Set1, Slot, Bkt) -> Set2 when
-      Set1 :: set(Element),
-      Set2 :: set(Element),
+      Set1 :: set_v1(Element),
+      Set2 :: set_v1(Element),
       Slot :: non_neg_integer(),
       Bkt :: [Element].
 update_bucket(Set, Slot, NewBucket) ->
@@ -946,7 +949,7 @@ filtermap(F, #set{}=D) when is_function(F, 1) ->
 %% get_slot(Hashdb, Key) -> Slot.
 %%  Get the slot.  First hash on the new range, if we hit a bucket
 %%  which has not been split use the unsplit buddy bucket.
--spec get_slot(set(E), E) -> non_neg_integer().
+-spec get_slot(set_v1(E), E) -> non_neg_integer().
 get_slot(T, Key) ->
     H = erlang:phash(Key, T#set.maxn),
     if
@@ -955,7 +958,7 @@ get_slot(T, Key) ->
     end.
 
 %% get_bucket(Hashdb, Slot) -> Bucket.
--spec get_bucket(set(), non_neg_integer()) -> term().
+-spec get_bucket(set_v1(_), non_neg_integer()) -> term().
 get_bucket(T, Slot) -> get_bucket_s(T#set.segs, Slot).
 
 %% fold_set(Fun, Acc, Dictionary) -> Dictionary.
@@ -1022,7 +1025,7 @@ put_bucket_s(Segs, Slot, Bkt) ->
     Seg = setelement(BktI, element(SegI, Segs), Bkt),
     setelement(SegI, Segs, Seg).
 
--spec maybe_expand(set(E)) -> set(E).
+-spec maybe_expand(set_v1(E)) -> set_v1(E).
 maybe_expand(T0) when T0#set.size + 1 > T0#set.exp_size ->
     T = maybe_expand_segs(T0),			%Do we need more segments.
     N = T#set.n + 1,				%Next slot to expand into
@@ -1040,14 +1043,14 @@ maybe_expand(T0) when T0#set.size + 1 > T0#set.exp_size ->
 	  segs = Segs2};
 maybe_expand(T) -> T#set{size = T#set.size + 1}.
 
--spec maybe_expand_segs(set(E)) -> set(E).
+-spec maybe_expand_segs(set_v1(E)) -> set_v1(E).
 maybe_expand_segs(T) when T#set.n =:= T#set.maxn ->
     T#set{maxn = 2 * T#set.maxn,
 	  bso  = 2 * T#set.bso,
 	  segs = expand_segs(T#set.segs, T#set.empty)};
 maybe_expand_segs(T) -> T.
 
--spec maybe_contract(set(E), non_neg_integer()) -> set(E).
+-spec maybe_contract(set_v1(E), non_neg_integer()) -> set(E).
 maybe_contract(T, Dc) when T#set.size - Dc < T#set.con_size,
 			   T#set.n > ?seg_size ->
     N = T#set.n,
-- 
2.51.0

openSUSE Build Service is sponsored by