gradient icon indicating copy to clipboard operation
gradient copied to clipboard

t() issues with struct!/2

Open alanvardy opened this issue 1 year ago • 1 comments

Code:

  @type t :: %__MODULE__{
          ..fields here
        }


  @doc false
  @spec new(map) :: t()
  def new(params) do
    struct!(__MODULE__, params)
  end

Error

The function call on line 44 is expected to have type t() but it has type struct()
42   @spec new(map) :: t()
43   def new(params) do
44     struct!(__MODULE__, params)
45   end
46 end

alanvardy avatar May 19 '23 23:05 alanvardy

Hey, Alan!

This requires an explicit downcast, since not every struct() is a valid t(). You know this particular one is, but the typechecker doesn't. That's where Gradient.TypeAnnotation comes in handy:

defmodule TestStruct do
  use Gradient.TypeAnnotation

  defstruct f: "some value"

  @type t :: %__MODULE__{
    :f => String.t()
  }

  @doc false
  @spec new(map) :: t()
  def new(params) do
    struct!(__MODULE__, params) |> assert_type(t())
  end
end

That way struct!/2 does the runtime check that params are valid for this particular struct, whereas assert_type(_, t()) let's the typechecker know that from now on it's not a general struct() type instance, but a proper t() instance.

erszcz avatar Jun 15 '23 11:06 erszcz