Qqwy / elixir-type_check

TypeCheck: Fast and flexible runtime type-checking for your Elixir projects.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

crash with `protocol Enumerable not implemented` error

marcandre opened this issue · comments

Following the fixes in last version, I bravely continued on my quest but quickly reached an impasse.

defmodule EmptyMix do
  defstruct [:name]
  use TypeCheck, enable_runtime_checks: Mix.env() != :prod
  @type! t :: %__MODULE__{name: String.t()}

  @spec! hello(%{String.t() => any} | t()) :: atom
  def hello(_struct), do: :ok
end

# Test:
defmodule EmptyMixTest do
  use ExUnit.Case
  doctest EmptyMix

  test "this works" do
    assert EmptyMix.hello(%{"a" => :b}) == :ok
  end

  test "this raises an error do
    assert EmptyMix.hello(%EmptyMix{name: "X"}) == :ok
  end
end

Error is:

     ** (Protocol.UndefinedError) protocol Enumerable not implemented for %EmptyMix{name: "X"} of type EmptyMix (a struct). This protocol is implemented for the following type(s): Date.Range, File.Stream, Function, GenEvent.Stream, HashDict, HashSet, IO.Stream, Jason.OrderedObject, List, Map, MapSet, Range, Stream, StreamData
     code: assert EmptyMix.hello(%EmptyMix{name: "X"}) == :ok
     stacktrace:
       (elixir 1.14.0) lib/enum.ex:1: Enumerable.impl_for!/1
       (elixir 1.14.0) lib/enum.ex:166: Enumerable.reduce/3
       (elixir 1.14.0) lib/enum.ex:2514: Enum.reduce_while/3
       (empty_mix 0.1.0) lib/type_check/spec.ex:54: EmptyMix.hello/1
       test/empty_mix_test.exs:10: (test)

The error occurs when passing a struct to a union type of which a non-struct map is one of the possibilities.

This will result in the first 'is_map' check being true, but then when calling Enum.reduce_while to check for the keys, balk at there not being an Enumerable implementation.

Either we need Enum.to_list :maps.to_list in some places before iterating over the map key-value pairs, or we need a defensive check to ensure that a struct is not allowed to reach that point. 🤔