While compiling the following functions I’m getting a warning that did not show in Elixir 1.18.x.
@impl Event
def to_payload(%GameTransactionCompleted{} = e) do
# ...
end
def to_payload(%GameTransactionCompleted.ExternalTransaction{} = e) do
# ...
end
def to_payload(%GameTransactionCompleted.InternalTransaction{} = e) do
# ...
end
def to_payload(%GameTransactionCompleted.Stake{} = s) do
# ...
end
def to_payload(%Game{} = g) do
# ...
end
Compiling 1 file (.ex)
warning: the 1st pattern in clause will never match:
%Dragonara.Outbox.GameTransactionCompleted.ExternalTransaction{} = e
because it is expected to receive type:
dynamic(%Dragonara.Outbox.GameTransactionCompleted{})
typing violation found at:
│
101 │ def to_payload(%GameTransactionCompleted.ExternalTransaction{} = e) do
│ ~
│
└─ lib/dragonara/outbox/game_transaction_completed.ex:101:68: Dragonara.Outbox.Event.Dragonara.Outbox.GameTransactionCompleted.to_payload/1
warning: the 1st pattern in clause will never match:
%Dragonara.Outbox.GameTransactionCompleted.InternalTransaction{} = e
because it is expected to receive type:
dynamic(%Dragonara.Outbox.GameTransactionCompleted{})
typing violation found at:
│
120 │ def to_payload(%GameTransactionCompleted.InternalTransaction{} = e) do
│ ~
│
└─ lib/dragonara/outbox/game_transaction_completed.ex:120:68: Dragonara.Outbox.Event.Dragonara.Outbox.GameTransactionCompleted.to_payload/1
warning: the 1st pattern in clause will never match:
%Dragonara.Outbox.GameTransactionCompleted.Stake{} = s
because it is expected to receive type:
dynamic(%Dragonara.Outbox.GameTransactionCompleted{})
typing violation found at:
│
140 │ def to_payload(%GameTransactionCompleted.Stake{} = s) do
│ ~
│
└─ lib/dragonara/outbox/game_transaction_completed.ex:140:54: Dragonara.Outbox.Event.Dragonara.Outbox.GameTransactionCompleted.to_payload/1
warning: the 1st pattern in clause will never match:
%Bluelabs.Game{} = g
because it is expected to receive type:
dynamic(%Dragonara.Outbox.GameTransactionCompleted{})
typing violation found at:
│
144 │ def to_payload(%Game{} = g) do
│ ~
│
└─ lib/dragonara/outbox/game_transaction_completed.ex:144:28: Dragonara.Outbox.Event.Dragonara.Outbox.GameTransactionCompleted.to_payload/1
warning: the 1st pattern in clause will never match:
nil
because it is expected to receive type:
dynamic(%Dragonara.Outbox.GameTransactionCompleted{})
typing violation found at:
│
171 │ def to_payload(nil) do
│ ~~~~~~~~~~~~~~~~~~~~~~
│
└─ lib/dragonara/outbox/game_transaction_completed.ex:171: Dragonara.Outbox.Event.Dragonara.Outbox.GameTransactionCompleted.to_payload/1
Generated dragonara app
Looks like the compiler is not able to understand that this is a multiclause function that acts differently depending on the struct that it receives. It is true that from the outside this function is only called with the %GameTransactionCompleted{} struct but that call also uses the other clauses for nested structs.
EDIT: I also want to note that if I rename the problematic clauses so they are not part of the same function (for example payload instead of to_payload) the warnings go away. While this workaround fixes the issue I still wonder if this should happen and why the compiler is not able to detect that the other clauses are also being called with the proper structs.
Oh, I think I got it. You literally have a protocol and then in one of the implementations, you define additional clauses.
Yes, the warning is expected. The type system is enforcing that you are implementing the protocol exactly for the type of that implementation. We could not emit any warning, but then it means someone may accidentally define additional clauses, and they won’t get any help from the type system. So we chose to enforce that the first argument matches the implementation.
If the description above is not correct, then please provide a way to reproduce this or post a larger code snippet. Thanks.
I have verified across multiple projects now. We did hit the issue in rc.1
But rc.2 seems solid.
I am deploying to some QA ENVs right now but things look really good.
Probably 20k unit tests across the projects we’ve updated. All passing.
Huge improvements.
Running with 1.19.0-rc.2 detected a huge cycle (length 171) that was not there before (1.18.4). I notice that only some modules in the cycle have the “compile” annotation, which seems suspicious.
Not sure how helpful this will be, but I tried compiling our largish project (3729 files; 119 kloc), and the overall elapsed time was noticeably slower than it was with 1.18 (this was the case with both Erlang 27 and 28):
According to your output they used the same amount of wall-time but different amount of CPU time if I read this correctly?
You’re right – I was reading the output wrong . The first time I ran it the real time was slower too (by around 10–20% iirc), but when I ran it while not doing anything else at the same time it evened out. Still seems slightly odd that it’s doing that much more work overall though, even if it’s making better use of all the cores.
Sorry @josevalim , just thought I’d check with you regarding the dialyzer errors, is this something you would like reported here or in a GH issue, or maybe not at all?