Dotty Documentation



[-] Constructors

[-] Members

[+] object DefaultShowAPI
[+] class ExtractAPI

This phase sends a representation of the API of classes to sbt via callbacks.

This is used by sbt for incremental recompilation.

See the documentation of ExtractAPICollector, ExtractDependencies, ExtractDependenciesCollector and for more information on incremental recompilation.

The following flags affect this phase: -Yforce-sbt-phases -Ydump-sbt-inc

[+] private class ExtractAPICollector

Extracts full (including private members) API representation out of Symbols and Types.

The exact representation used for each type is not important: the only thing that matters is that a binary-incompatible or source-incompatible change to the API (for example, changing the signature of a method, or adding a parent to a class) should result in a change to the API representation so that sbt can recompile files that depend on this API.

Note that we only records types as they are defined and never "as seen from" some other prefix because Types#asSeenFrom is a complex operation and doing it for every inherited member would be slow, and because the number of prefixes can be enormous in some cases:

class Outer { type T <: S type S class A extends Outer { /.../ } class B extends Outer { /.../ } class C extends Outer { /.../ } class D extends Outer { /.../ } class E extends Outer { /.../ } }

S might be refined in an arbitrary way inside A for example, this affects the type of T as seen from Outer#A, so we could record that, but the class A also contains itself as a member, so Outer#A#A#A#... is a valid prefix for T. Even if we avoid loops, we still have a combinatorial explosion of possible prefixes, like Outer#A#B#C#D#E.

It is much simpler to record T once where it is defined, but that means that the API representation of T may not change even though T as seen from some prefix has changed. This is why in ExtractDependencies we need to traverse used types to not miss dependencies, see the documentation of ExtractDependencies#usedTypeTraverser.

TODO: sbt does not store the full representation that we compute, instead it hashes parts of it to reduce memory usage, then to see if something changed, it compares the hashes instead of comparing the representations. We should investigate whether we can just directly compute hashes in this phase without going through an intermediate representation, see

This phase sends information on classes' dependencies to sbt via callbacks.

This is used by sbt for incremental recompilation. Briefly, when a file changes sbt will recompile it, if its API has changed (determined by what ExtractAPI sent) then sbt will determine which reverse-dependencies (determined by what ExtractDependencies sent) of the API have to be recompiled depending on what changed.

See the documentation of ExtractDependenciesCollector, ExtractAPI, ExtractAPICollector and for more information on how sbt incremental compilation works.

The following flags affect this phase: -Yforce-sbt-phases -Ydump-sbt-inc

[+] private class ExtractDependenciesCollector

Extract the dependency information of a compilation unit.

To understand why we track the used names see the section "Name hashing algorithm" in To understand why we need to track dependencies introduced by inheritance specially, see the subsection "Dependencies introduced by member reference and inheritance" in the "Name hashing algorithm" section.

[+] private object SafeLazy
[+] private object SafeLazyWrapper

Wrapper around SafeLazy implementations.

xsbti.SafeLazy is part of sbt but it is not part of the interface jar that dotty depends on, therefore we can only access it by reflection, and this will only succeed when dotty is run by sbt (otherwise xsbti.SafeLazy won't be on the classpath at all).

For testing purposes, we still want to be able to run the sbt phases outside of sbt, using -Yforce-sbt-phases and -Ydump-sbt-inc, therefore we provide a copy of SafeLazy in that we use when xsbti.SafeLazy is unavailable.

This raises a question: why bother with xsbti.SafeLazy if we have our own version anyway? Because sbt uses Java serialization to persist the output of the incremental compilation analysis when sbt is stopped and restarted. If we used with sbt, deserialization would fail and every restart of sbt would require a full recompilation.

Note: this won't be needed once we switch to zinc 1.0 where SafeLazy becomes part of the interface jar, see

[+] object ShowAPI
[+] trait ThunkHolder

Create and hold thunks. A thunk is a (potentially) unevaluated value that may be evaluated once.