1

I have an umbrella app. I see the value of Dialyzer and I'm trying to get started with it. I've gotten pretty far but I have an issue around Ecto I cannot solve.

This is for a small App in the umbrella that handles Authentication. I can trim it all down the simplest example.

Using Elixir 1.4.2 and Dialyxir 0.4.0.

Code in Question

defmodule Auth.Account do
  use Ecto.Schema
  import Ecto.Changeset

  schema "auth_accounts" do
    field :email, :string
    field :password_hash, :string
    field :password, :string, virtual: true

    timestamps()
  end

  def build(params \\ %{}) do
    changeset(%__MODULE__{}, params)
  end

  def changeset(account, params \\ %{}) do
    account
    |> cast(params, ~w(email password))
  end
end

Relevant Error Output

lib/auth/account.ex:13: Function build/0 has no local return
lib/auth/account.ex:13: Function build/1 has no local return
lib/auth/account.ex:14: The call 'Elixir.Auth.Account':changeset(#{'__meta__':=#{'__struct__':='Elixir.Ecto.Schema.Metadata', 'context':='nil', 'source':={'nil',<<_:104>>}, 'state':='built'}, '__struct__':='Elixir.Auth.Account', 'email':='nil', 'id':='nil', 'inserted_at':='nil', 'password':='nil', 'password_hash':='nil', 'updated_at':='nil'},params@1::any()) 
  will never return since it differs in the 1st argument from the success typing arguments: ({map(),map()} | #{'__struct__':=atom(), 'action'=>'delete' | 'insert' | 'nil' | 'replace' | 'update', 'changes'=>#{atom()=>_}, 'constraints'=>[#{'constraint':=binary(), 'field':=atom(), 'match':='exact' | 'suffix', 'message':={_,_}, 'type':='unique'}], 'data'=>'nil' | #{'__struct__':=atom()}, 'empty_values'=>_, 'errors'=>[{atom(),{_,_}}], 'filters'=>#{atom()=>_}, 'params'=>'nil' | #{binary()=>_}, 'prepare'=>[fun((map()) -> map())], 'repo'=>atom(), 'required'=>[atom()], 'types'=>'nil' | #{atom()=>atom() | {'array',_} | {'embed',map()} | {'in',_} | {'map',_}}, 'valid?'=>boolean(), 'validations'=>[{atom(),_}]},'invalid' | #{'__struct__'=>none(), atom() | binary()=>_})

It appears the problem is around the build function's use of %__MODULE__{}. See this related Stack Overflow Topic.

However, I just can't figure out a valid alternate syntax.

Community
  • 1
  • 1
Mark Eric
  • 693
  • 1
  • 6
  • 13
  • Does this fix the warning? `def build(params \\ %{}) do`? – Dogbert Feb 28 '17 at 20:02
  • Unfortunately not. I updated the code above so that doesn't confuse others. But I just re-tested to verify. The problem remains. Rebuilt the PLT to be sure. – Mark Eric Feb 28 '17 at 21:58
  • Scratch that, I'm unable to reproduce this locally if I copy paste your exact code in a new mix package. What version of Ecto are you using? Are you able to reproduce this if you copy that module to a brand new mix package? (FWIW I don't think this error is related to the other question you linked to.) – Dogbert Mar 01 '17 at 05:16

1 Answers1

1

Dogbert prompted me to dig deeper by not being able to reproduce it.

I was on ecto ~> 2.0. The mix.lock file had me at 2.0.5. After mix deps.unlock --all and a mix deps.clean --all and mix deps.get, I was moved up to ecto 2.1.3.

After the library upgrades, dialyzer no longer complained about this. So my fix was to upgrade to a newer ecto version.

Mark Eric
  • 693
  • 1
  • 6
  • 13