Skip to content

Commit e622a26

Browse files
committed
Properly preserve function dynamic type on application
1 parent 72435c4 commit e622a26

File tree

3 files changed

+17
-12
lines changed

3 files changed

+17
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ It is also possible to mix domain keys, as above, with atom keys, yielding the f
5252
%{integer() => integer(), root: integer()}
5353
```
5454

55-
This system is an implementation of [Polymorphic Records for Dynamic Languages, by Giuseppe Castagna and Loïc Peyrot (2024)](https://arxiv.org/abs/2404.00338).
55+
This system is an implementation of [Typing Records, Maps, and Structs, by Giuseppe Castagna (2023)](https://www.irif.fr/~gc/papers/icfp23.pdf).
5656

5757
### Typing of map operations
5858

lib/elixir/lib/module/types/apply.ex

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -365,14 +365,14 @@ defmodule Module.Types.Apply do
365365
{{:strong, nil, [{domain, open_map()}]}, domain, context}
366366
end
367367

368-
def remote_domain(Map, :pop!, [_, key], expected, _meta, _stack, context) when is_atom(key) do
369-
domain = [open_map([{key, expected}]), term()]
370-
{{:strong, nil, [{domain, open_map()}]}, domain, context}
368+
def remote_domain(Map, :pop!, [_, key], _expected, _meta, _stack, context) when is_atom(key) do
369+
domain = [open_map([{key, term()}]), term()]
370+
{{:strong, nil, [{domain, tuple([term(), open_map()])}]}, domain, context}
371371
end
372372

373-
def remote_domain(Map, :update!, [_, key, _], expected, _meta, _stack, context)
373+
def remote_domain(Map, :update!, [_, key, _], _expected, _meta, _stack, context)
374374
when is_atom(key) do
375-
domain = [open_map([{key, expected}]), term(), fun(1)]
375+
domain = [open_map([{key, term()}]), term(), fun(1)]
376376
{{:strong, nil, [{domain, open_map()}]}, domain, context}
377377
end
378378

@@ -540,10 +540,10 @@ defmodule Module.Types.Apply do
540540
_ -> {map, default}
541541
end
542542

543-
{map, fun} =
543+
map =
544544
case fun do
545-
%{dynamic: fun} -> {dynamic(map), fun}
546-
_ -> {map, fun}
545+
%{dynamic: _} -> dynamic(map)
546+
_ -> map
547547
end
548548

549549
fun_apply = fn optional?, arg_type ->
@@ -1059,10 +1059,10 @@ defmodule Module.Types.Apply do
10591059

10601060
def map_update_or_replace_lazy(name, [map, key, fun] = args_types, stack, error) do
10611061
try do
1062-
{map, fun} =
1062+
map =
10631063
case fun do
1064-
%{dynamic: fun} -> {dynamic(map), fun}
1065-
_ -> {map, fun}
1064+
%{dynamic: _} -> dynamic(map)
1065+
_ -> map
10661066
end
10671067

10681068
fun_apply = fn optional?, arg_type ->

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,6 +1357,11 @@ defmodule Module.Types.MapTest do
13571357
(:bar -> dynamic(:value))
13581358
"""
13591359
end
1360+
1361+
test "with unknown function type" do
1362+
assert typecheck!([x], Map.update!(x, :body, &:zlib.gunzip/1)) ==
1363+
dynamic(open_map(body: term()))
1364+
end
13601365
end
13611366

13621367
describe "Map.values/1" do

0 commit comments

Comments
 (0)