Skip to content

Container type constructors drop static parts of gradual element types #15273

@lukaszsamson

Description

@lukaszsamson

Elixir and Erlang/OTP versions

Erlang/OTP 28 [erts-16.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit]

Interactive Elixir (1.20.0-rc.4)

Operating system

any

Current behavior

tuple/1, closed_map/1, open_map/1, non_empty_list/1,2 discard the static component of gradual element types, producing dynamic-only containers. This breaks subtype relation
Repro:

import Module.Types.Descr

# NOTE static and dynamic part
x = union(atom([:ok]), dynamic(integer()))                                                                                                                                                                   
%{atom: {:union, %{ok: []}}, dynamic: %{atom: {:union, %{ok: []}}, bitmap: 8}}

# subtype holds
subtype?(atom([:ok]), x)
true

# NOTE only dynamic
tuple([x])
%{dynamic: %{tuple: {:closed, [%{atom: {:union, %{ok: []}}, bitmap: 8}]}}}
closed_map(a: x)
%{dynamic: %{map: {:closed, [a: %{atom: {:union, %{ok: []}}, bitmap: 8}]}}}
open_map(a: x)
%{dynamic: %{map: {:open, [a: %{atom: {:union, %{ok: []}}, bitmap: 8}]}}}
non_empty_list(x)
%{dynamic: %{list: {%{atom: {:union, %{ok: []}}, bitmap: 8}, %{bitmap: 4}}}}

# subtype does not hold
subtype?(tuple([atom([:ok])]), tuple([x]))
false
subtype?(closed_map(a: atom([:ok])), closed_map(a: x))
false
subtype?(open_map(a: atom([:ok])), open_map(a: x))
false
subtype?(non_empty_list(atom([:ok])), non_empty_list(x))
false

Cause: All three constructors call :maps.take(:dynamic, value) on element types and use only the dynamic part, discarding _static:

Expected behavior

Constructors should split the element into static and dynamic parts, building both a static container and a dynamic container. There are tests asserting existing dynamic hoisting behavior:

dynamic(open_map(a: integer())) == open_map(a: dynamic(integer()))

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions