Hi,
I have the following module:
defmodule MyApp.Payment
use Ecto.Schema
import Ecto.Changeset
schema "payment" do
field :booking_uuid, :string
belongs_to :booking, Kraken.Bookings.Booking
end
@spec update_payment_booking(__MODULE__, integer(), String.t()) :: Ecto.Changeset.t()
def update_payment_booking(payment, booking_id, booking_uuid) do
payment
|> change(%{booking_id: booking_id, booking_uuid: booking_uuid})
end
end
VS code highlights this spec with a warning stating it is invalid. I don’t understand this as the function takes an instance of itself, an integer and a string, returning a changeset. When I ask VS code to auto complete it for me, it replaces it with:
@spec update_payment_booking(
{map, map}
| %{
:__struct__ => atom | %{:__changeset__ => any, optional(any) => any},
optional(atom) => any
},
any,
any
) :: Ecto.Changeset.t()
Can someone please run me through why it thinks my spec is wrong?
Thanks in advance
Can you show us the callers of that function? Maybe indeed some of them pass a tuple as a first parameter to it?
Thanks for replying,
Sure, it gets called once in my codebase:
defp handle_confirm_booking_response({:ok, %{booking: booking}}, payment) do
updated_payment =
Payment.update_payment_booking(payment, booking.id, booking.uuid)
|> Payment.update_payment_status(:captured)
|> Repo.update!()
And I can confirm the first argument in that payment is indeed a Payment struct.
Just for my own info does that mean dialyzer will mark a spec as invalid if it is called with different arguments in a different module? I assumed it would just highlight the offending call rather than the spec itself,
Thanks
I don’t think the __MODULE__
looks right there. It resolves to MyApp.Payment
which is the atom :"Elixir.MyApp.Payment
and it looks like you’re passing in an instance of the of the schema. Did you mean to write %__MODULE__{}
instead?
Or you could do something like
@opaque t :: %__MODULE__{}
@spec update_payment_booking(t(), integer(), String.t()) :: Ecto.Changeset.t()`
(Edited to s/your/you’re/)
2 Likes
I can confirm %__MODULE__{}
clears the warning - Thanks for your explanation which makes sense!
1 Like
You probably want __MODULE__.t()
. There was even recent discussion here or simply t()
as @paulanthonywilson pointed out.
2 Likes