Skip to content

Commit 9fc3708

Browse files
committed
Fix optimizations for closed map checking (#14813)
1 parent c06b6a9 commit 9fc3708

File tree

2 files changed

+99
-3
lines changed

2 files changed

+99
-3
lines changed

lib/elixir/lib/module/types/descr.ex

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3363,10 +3363,10 @@ defmodule Module.Types.Descr do
33633363
true
33643364

33653365
# The keys is only in the negative map, and the positive map is closed
3366-
# in that case, this field is not_set(), and its difference with the negative map type is empty iff
3367-
# the negative type is optional.
3366+
# in that case, this field is not_set(), and its difference with the
3367+
# negative map type is empty iff the negative type is optional.
33683368
tag == :closed ->
3369-
is_optional_static(neg_type) or map_line_empty?(tag, fields, negs)
3369+
is_optional_static(neg_type) or throw(:closed)
33703370

33713371
# There may be value in common
33723372
tag == :open ->
@@ -3391,6 +3391,9 @@ defmodule Module.Types.Descr do
33913391
neg_tag == :open ->
33923392
true
33933393

3394+
neg_tag == :closed and not is_optional_static(type) ->
3395+
throw(:closed)
3396+
33943397
true ->
33953398
# an absent key in a open negative map can be ignored
33963399
diff = difference(type, neg_atom_default)
@@ -3401,6 +3404,8 @@ defmodule Module.Types.Descr do
34013404
else
34023405
map_line_empty?(tag, fields, negs)
34033406
end
3407+
catch
3408+
:closed -> map_line_empty?(tag, fields, negs)
34043409
end
34053410

34063411
# Verify the domain condition from equation (22) in paper ICFP'23 https://www.irif.fr/~gc/papers/icfp23.pdf

lib/elixir/test/elixir/module/types/descr_test.exs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2505,5 +2505,96 @@ defmodule Module.Types.DescrTest do
25052505
refute subtype?(map1, map2)
25062506
assert subtype?(map2, map1)
25072507
end
2508+
2509+
test "struct difference" do
2510+
entries =
2511+
[
2512+
closed_map(__struct__: atom([MapSet]), map: term()),
2513+
closed_map(__struct__: atom([Jason.OrderedObject]), values: term()),
2514+
closed_map(__struct__: atom([GenEvent.Stream]), timeout: term(), manager: term()),
2515+
closed_map(__struct__: atom([HashDict]), size: term(), root: term()),
2516+
closed_map(__struct__: atom([HashSet]), size: term(), root: term()),
2517+
closed_map(
2518+
__struct__: atom([IO.Stream]),
2519+
raw: term(),
2520+
device: term(),
2521+
line_or_bytes: term()
2522+
),
2523+
closed_map(__struct__: atom([Range]), first: term(), last: term(), step: term()),
2524+
closed_map(
2525+
__struct__: atom([Stream]),
2526+
enum: term(),
2527+
done: term(),
2528+
funs: term(),
2529+
accs: term()
2530+
),
2531+
closed_map(
2532+
__struct__: atom([Req.Response.Async]),
2533+
pid: term(),
2534+
ref: term(),
2535+
stream_fun: term(),
2536+
cancel_fun: term()
2537+
),
2538+
closed_map(
2539+
__struct__: atom([Postgrex.Stream]),
2540+
options: term(),
2541+
params: term(),
2542+
query: term(),
2543+
conn: term()
2544+
),
2545+
closed_map(
2546+
__struct__: atom([DBConnection.PrepareStream]),
2547+
opts: term(),
2548+
params: term(),
2549+
query: term(),
2550+
conn: term()
2551+
),
2552+
closed_map(
2553+
__struct__: atom([DBConnection.Stream]),
2554+
opts: term(),
2555+
params: term(),
2556+
query: term(),
2557+
conn: term()
2558+
),
2559+
closed_map(
2560+
__struct__: atom([Ecto.Adapters.SQL.Stream]),
2561+
meta: term(),
2562+
opts: term(),
2563+
params: term(),
2564+
statement: term()
2565+
),
2566+
closed_map(
2567+
__struct__: atom([Date.Range]),
2568+
first: term(),
2569+
last: term(),
2570+
step: term(),
2571+
first_in_iso_days: term(),
2572+
last_in_iso_days: term()
2573+
),
2574+
closed_map(
2575+
__struct__: atom([File.Stream]),
2576+
node: term(),
2577+
raw: term(),
2578+
path: term(),
2579+
modes: term(),
2580+
line_or_bytes: term()
2581+
),
2582+
closed_map(
2583+
__struct__: atom([Phoenix.LiveView.LiveStream]),
2584+
name: term(),
2585+
ref: term(),
2586+
inserts: term(),
2587+
deletes: term(),
2588+
reset?: term(),
2589+
dom_id: term(),
2590+
consumable?: term()
2591+
)
2592+
]
2593+
2594+
range =
2595+
closed_map(__struct__: atom([Range]), first: integer(), last: integer(), step: integer())
2596+
2597+
assert subtype?(range, Enum.reduce(entries, &union/2))
2598+
end
25082599
end
25092600
end

0 commit comments

Comments
 (0)