# `Rho.Dyn.Trace`
[🔗](https://github.com/GenericJam/rho/blob/v0.1.0/lib/rho/dyn/trace.ex#L1)

An Elixir compiler tracer for Dyn compiles (`Code.put_compiler_option(:tracers, ...)`):
which modules of the generation a file needs **at compile time**, so
`Rho.Dyn.Compiler` knows when a file compiled for an earlier
generation can be reused as it is (`Rho.Dyn.Reuse`).

A file needs module `M` at compile time when it expands `%M{}`, imports
or requires `M`, uses one of its macros, or calls `M` outside a function
body (in a module attribute, say): its compiled code then depends on
`M`'s code, not only on its name. Calls inside function bodies only name
`M` and don't count.

It records only while `collect/2` runs in the calling process (the
tracer runs in the process that expands the code), so other compiles in
the VM are untouched. `collect/2` also reports the modules the file
defined (`:on_module`); a caller that sees fewer than it compiled treats
the file's needs as unknown.

It is also the gate on what a Dyn compile may define, before anything
loads (`guard/3`, in the compiling process): when a module's definition
starts (`:defmodule`) it is reported to the compiler, which undoes what
the compile defined outside the generation, and refused (the compile of
that file fails) unless it is `<ns>.G<n>.*` (the namespace,
`Rho.Dyn.Config`) or named as a protocol's implementation for one
(`Inspect.<ns>.G<n>.X`, with
`Inspect` a protocol). A `Protocol.derive/2` for a stdlib type or a
library macro's module elsewhere never replaces anything.

# `allowed?`

```elixir
@spec allowed?(module(), String.t()) :: boolean()
```

May a compile for generation `own` (`"Elixir.Dyn.G<n>."`) define
`mod`: one of its own, or a protocol's implementation for one?

# `collect`

```elixir
@spec collect(String.t(), (-&gt; result)) ::
  {result, %{defined: MapSet.t(module()), needs: MapSet.t(module())}}
when result: term()
```

Runs `fun` (one file's compile) and returns its result with what it
traced: the modules defined and the modules named `prefix*` it needed
at compile time.

# `guard`

```elixir
@spec guard(pos_integer(), pid(), reference()) :: :ok
```

From now on in this process, every module definition that starts is
sent to `pid` as `{ref, :defmodule, module, prior}` (`prior`: the md5
and file of the version loaded under that name until then, or nil), and
one outside generation `n` (see the moduledoc) raises instead of being
defined.

# `install`

```elixir
@spec install() :: :ok
```

Adds this tracer to the compiler's (once per VM).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
