### Elixir and Erlang/OTP versions
Elixir 1.18.4
OTP-28.0
(both installed with …Mise)
### Operating system
Ubuntu 25.04
### Current behavior
When using dialyzer to check the following Elixir Code
```elixir
defmodule Foo do
@spec foo() :: Ecto.Multi.t()
def foo() do
Ecto.Multi.new()
end
end
```
we get the following Warning:
```
lib/foo.ex:2:contract_with_opaque
The @spec for Foo.foo/0 has an opaque
subtype %Ecto.Multi{
:names => %MapSet{:map => MapSet.internal(_)},
:operations => [
{_,
{:inspect, Keyword.t()}
| {:merge,
(map() -> %Ecto.Multi{:names => map(), :operations => [{_, _}], _ => _})
| {atom(), atom(), [any()]}}
| {:put, _}
| {:run, (atom(), map() -> {:error, _} | {:ok, _})}
| {:changeset,
%Ecto.Changeset{
:action => atom(),
:changes => %{atom() => _},
:constraints => [
%{
:constraint =>
binary()
| %Regex{
:opts => binary() | [any()],
:re_pattern => _,
:re_version => _,
:source => binary()
},
:error_message => binary(),
:error_type => atom(),
:field => atom(),
:match => :exact | :prefix | :suffix,
:type => :check | :exclusion | :foreign_key | :unique
}
],
:data => nil | map(),
:empty_values => _,
:errors => Keyword.t({binary(), Keyword.t()}),
:filters => %{atom() => _},
:params => nil | %{binary() => _},
:prepare => [(_ -> any())],
:repo => atom(),
:repo_opts => Keyword.t(),
:required => [atom()],
:types => %{
atom() =>
atom()
| {:array | :assoc | :embed | :in | :map | :parameterized | :supertype | :try,
_}
},
:valid? => boolean(),
:validations => Keyword.t()
}, Keyword.t()}
| {:delete_all,
%Ecto.Query{
:aliases => _,
:assocs => _,
:combinations => _,
:distinct => _,
:from => _,
:group_bys => _,
:havings => _,
:joins => _,
:limit => _,
:lock => _,
:offset => _,
:order_bys => _,
:prefix => _,
:preloads => _,
:select => _,
:sources => _,
:updates => _,
:wheres => _,
:windows => _,
:with_ctes => _
}, Keyword.t()}
| {:update_all,
%Ecto.Query{
:aliases => _,
:assocs => _,
:combinations => _,
:distinct => _,
:from => _,
:group_bys => _,
:havings => _,
:joins => _,
:limit => _,
:lock => _,
:offset => _,
:order_bys => _,
:prefix => _,
:preloads => _,
:select => _,
:sources => _,
:updates => _,
:wheres => _,
:windows => _,
:with_ctes => _
}, Keyword.t()}
| {:insert_all, atom() | binary() | {binary(), atom()}, [Keyword.t() | map()],
Keyword.t()}}
]
} which is violated by the success typing.
Success typing:
() :: %Ecto.Multi{:names => %MapSet{:map => %{}}, :operations => []}
```
I have another code snippet to reproduce which I suspect is related to the same issue.
```elixir
defmodule MapsetDialyzer do
@spec bar(MapSet.t()) :: term()
def bar(set) do
set
end
def foo() do
bar(MapSet.new([1,2,3]))
end
end
```
Dialyzer gives this warning:
```
The call 'Elixir.MapsetDialyzer':bar
(#{'__struct__' => 'Elixir.MapSet',
'map' => #{1 => [], 2 => [], 3 => []}}) does not have a term of type
#{'__struct__' := 'Elixir.MapSet',
'map' := 'Elixir.MapSet':internal(_)} (with opaque subterms) as 1st argument
```
I suspect the error comes from how Elixir defines its MapSet Type. (https://github.com/elixir-lang/elixir/blob/7b20c281d521aa7aa2ad2baa1e9ae6c579d79d0c/lib/elixir/lib/map_set.ex#L53-L57)
### Expected behavior
Dialyzer not returning a warning.