[source]

compiler/iface/MkIface.hs

Note [Fingerprinting IfaceDecls]

[note link]

The general idea here is that we first examine the ‘IfaceDecl’s and determine the recursive groups of them. We then walk these groups in dependency order, serializing each contained ‘IfaceDecl’ to a “Binary” buffer which we then hash using MD5 to produce a fingerprint for the group.

However, the serialization that we use is a bit funny: we override the @putName@ operation with our own which serializes the hash of a ‘Name’ instead of the ‘Name’ itself. This ensures that the fingerprint of a decl changes if anything in its transitive closure changes. This trick is why we must be careful about traversing in dependency order: we need to ensure that we have hashes for everything referenced by the decl which we are fingerprinting.

Moreover, we need to be careful to distinguish between serialization of binding Names (e.g. the ifName field of a IfaceDecl) and non-binding (e.g. the ifInstCls field of a IfaceClsInst): only in the non-binding case should we include the fingerprint; in the binding case we shouldn’t since it is merely the name of the thing that we are currently fingerprinting.

Note [The ABI of an IfaceDecl]

[note link]

The ABI of a declaration consists of:

  1. the full name of the identifier (inc. module and package, because these are used to construct the symbol name by which the identifier is known externally).
(b) the declaration itself, as exposed to clients.  That is, the
    definition of an Id is included in the fingerprint only if
    it is made available as an unfolding in the interface.
(c) the fixity of the identifier (if it exists)
(d) for Ids: rules
(e) for classes: instances, fixity & rules for methods
(f) for datatypes: instances, fixity & rules for constrs

Items (c)-(f) are not stored in the IfaceDecl, but instead appear elsewhere in the interface file. But they are fingerprinted with the declaration itself. This is done by grouping (c)-(f) in IfaceDeclExtras, and fingerprinting that as part of the declaration.

Note [Original module]

[note link]

Consider this:
module X where { data family T } module Y( T(..) ) where { import X; data instance T Int = MkT Int }
The exported Avail from Y will look like
X.T{X.T, Y.MkT}
That is, in Y,
  • only MkT is brought into scope by the data instance;
  • but the parent (used for grouping and naming in T(..) exports) is X.T
  • and in this case we export X.T too

In the result of MkIfaceExports, the names are grouped by defining module, so we may need to split up a single Avail into multiple ones.

Note [Internal used_names]

[note link]

Most of the used_names are External Names, but we can have Internal Names too: see Note [Binders in Template Haskell] in Convert, and #5362 for an example. Such Names are always

  • Such Names are always for locally-defined things, for which we don’t gather usage info, so we can just ignore them in ent_map
  • They are always System Names, hence the assert, just as a double check.