Compilation warnings when trying to compile Phoenix app with circular dependencies

I’ve got a Phoenix project with some of the following Ecto schemas:

defmodule Daydream.Accounts.Tenant.Activation do
  use Ecto.Schema

  import Ecto.Changeset

  @type t() :: %__MODULE__{}
  alias __MODULE__

  @derive Jason.Encoder
  schema "tenant_activations" do
    field(:activated_at, :naive_datetime)

    belongs_to(:tenant, Daydream.Accounts.Tenant)

    timestamps()
  end
end
defmodule Daydream.Accounts.Tenant.Deactivation do
  use Ecto.Schema

  import Ecto.Changeset

  @type t() :: %__MODULE__{}
  alias __MODULE__

  @derive Jason.Encoder
  schema "tenant_deactivations" do
    field(:deactivated_at, :naive_datetime)

    belongs_to(:tenant, Daydream.Accounts.Tenant)

    timestamps()
  end

  @doc false
  def changeset(%Deactivation{} = deactivation, tenant) do
    deactivation
    |> change(%{deactivated_at: NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)})
    |> put_assoc(:tenant, tenant)
  end
end

and then the Tenant module:

defmodule Daydream.Accounts.Tenant do
  use Ecto.Schema
  import Ecto.Changeset

  @type t() :: %__MODULE__{}
  alias __MODULE__
  alias Daydream.HomeShare

  schema "tenants" do
    #.....
    has_many :activations, Daydream.Accounts.Tenant.Activation
    has_many :deactivations, Daydream.Accounts.Tenant.Deactivation
  end
end

this generates the following warnings on the compiler:

warning: invalid association `activations` in schema Daydream.Accounts.Tenant: associated schema Daydream.Accounts.Tenant.Activation does not exist
  lib/daydream/accounts/tenant.ex:1: Daydream.Accounts.Tenant (module)

warning: invalid association `deactivations` in schema Daydream.Accounts.Tenant: associated schema Daydream.Accounts.Tenant.Deactivation does not exist
  lib/daydream/accounts/tenant.ex:1: Daydream.Accounts.Tenant (module)

However, if I try to require the Activation and Deactivation modules in Tenant, then I see:

warning: invalid association `tenant` in schema Daydream.Accounts.Tenant.Activation: associated schema Daydream.Accounts.Tenant does not exist
  lib/daydream/accounts/tenants/activation.ex:1: Daydream.Accounts.Tenant.Activation (module)

warning: invalid association `tenant` in schema Daydream.Accounts.Tenant.Deactivation: associated schema Daydream.Accounts.Tenant does not exist
  lib/daydream/accounts/tenants/deactivation.ex:1: Daydream.Accounts.Tenant.Deactivation (module)

but then if I require tenant in those files, obviously that causes a deadlock:

== Compilation error in file lib/daydream/accounts/tenants/activation.ex ==
** (CompileError)  deadlocked waiting on module Daydream.Accounts.Tenant
    (stdlib 3.11.2) erl_eval.erl:680: :erl_eval.do_apply/6
    (elixir 1.10.0) lib/kernel/parallel_compiler.ex:233: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

Is there a way I can silence these warnings without creating deadlock, I assumed require was the way to go, but is there a better approach?

I just loaded your code into a sample project and can’t repro. What version of Ecto are you using?

Edit: My mix.lock file shows Ecto 3.4.5

It helps if you always start with rm -rf _build/ deps/ && mix do deps.get, compile and see if the error persists.

2 Likes