             {files, waiting}
           else
             files = update_timing(files, file_pid, :compiling)
-            {files, [{kind, child_pid, ref, file_pid, on, defining, deadlock?} | waiting]}
+            {files, Map.put(waiting, child_pid, {kind, ref, file_pid, on, defining, deadlock?})}
           end
 
         spawn_workers(queue, spawned, waiting, files, result, warnings, state)

  # The goal of this function is to find leaves in the dependency graph,
  # i.e. to find code that depends on code that we know is not being defined.
  # Note that not all files have been compiled yet, so they may not be in waiting.
  defp without_definition(waiting, files) do
    nilify_empty(
      for %{pid: pid} <- files,
          {_, _, ref, ^pid, on, _, _} <- waiting,
          not defining?(on, waiting),
          do: {ref, :not_found}
    )
  end

  defp deadlocked(waiting, type, defining?) do
    nilify_empty(
      for {_, _, ref, _, on, _, ^type} <- waiting,
          defining?(on, waiting) == defining?,
          do: {ref, :deadlock}
    )
  end

  defp defining?(on, waiting) do
    Enum.any?(waiting, fn {_, _, _, _, _, defining, _} -> on in defining end)
  end

  defp nilify_empty([]), do: nil
  defp nilify_empty([_ | _] = list), do: list

  # Wait for messages from child processes
  defp wait_for_messages(queue, spawned, waiting, files, result, warnings, state) do

          wait_for_messages(queue, new_spawned, waiting, new_files, result, warnings, state)
        end
    end
  end

  defp delete_waiting(waiting, pid) do
    Map.delete(waiting, pid)
  end

  defp update_timing(files, pid, key) do
