Opened 3 years ago

Closed 2 years ago

Last modified 2 years ago

#9252 closed feature request (invalid)

Generalize hs-boot files to be more like module signatures

Reported by: ezyang Owned by:
Priority: normal Milestone:
Component: Compiler Version: 7.8.2
Keywords: backpack Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s): Phab:D130
Wiki Page:


Right now, hs-boot is used solely to support mutually recursive modules. However, as Backpack has shown, signatures are an essential part of separate modular development, and since hs-boot files are essentially module signatures, it would be good to move away from "hs-boot as a technical mechanism to make mutual recursion to work" to "hsig as a module signature useful for separate modular development and mutual recursion."

Here are some of the things that this would entail:

  1. Introduce hsig as a valid alternate file suffix to hs-boot (similarly have hisig for hi-boot; the plan being to eventually deprecate the hs-boot prefix)
  1. Given an hsig file corresponding to a module in the current package database (but not from the currently being compiled package), check if the corresponding module implements the signature (this is the reverse of the current check we do for hs-boot files, which occurs when we typecheck the module, as opposed to the hs-boot file.)

Change History (9)

comment:1 Changed 3 years ago by ezyang

Differential Rev(s):

comment:2 Changed 3 years ago by rodlogic

@ezyang: a slight bike-shedding ... what about .hsi or .ihs instead of .hsig?

comment:3 Changed 3 years ago by thoughtpolice

Differential Rev(s):

comment:4 Changed 3 years ago by Edward Z. Yang <ezyang@…>

In aa4799534225e3fc6bbde0d5e5eeab8868cc3111/ghc:

Implementation of hsig (module signatures), per #9252

Module signatures, like hs-boot files, are Haskell modules which omit
value definitions and contain only signatures.  This patchset implements
one particular aspect of module signature, namely compiling them against
a concrete implementation.  It works like this: when we compile an hsig
file, we must be told (via the -sig-of flag) what module this signature
is implementing.  The signature is compiled into an interface file which
reexports precisely the entities mentioned in the signature file.  We also
verify that the interface is compatible with the implementation.

This feature is useful in a few situations:

    1. Like explicit import lists, signatures can be used to reduce
    sensitivity to upstream changes.  However, a signature can be defined
    once and then reused by many modules.

    2. Signatures can be used to quickly check if a new upstream version
    is compatible, by typechecking just the signatures and not the actual

    3. A signature can be used to mediate separate modular development,
    where the signature is used as a placeholder for functionality which
    is loaded in later.  (This is only half useful at the moment, since
    typechecking against signatures without implementations is not implemented
    in this patchset.)

Unlike hs-boot files, hsig files impose no performance overhead.

This patchset punts on the type class instances (and type families) problem:
instances simply leak from the implementation to the signature.  You can
explicitly specify what instances you expect to have, and those will be checked,
but you may get more instances than you asked for.  Our eventual plan is
to allow hiding instances, but to consider all transitively reachable instances
when considering overlap and soundness.

ToDo: signature merging: when a module is provided by multiple signatures
for the same base implementation, we should not consider this ambiguous.

ToDo: at the moment, signatures do not constitute use-sites, so if you
write a signature for a deprecated function, you won't get a warning
when you compile the signature.

Future work: The ability to feed in shaping information so that we can take
advantage of more type equalities than might be immediately evident.

Signed-off-by: Edward Z. Yang <>

Test Plan: validate and new tests

Reviewers: simonpj, simonmar, hvr, austin

Subscribers: simonmar, relrod, ezyang, carter, goldfire

Differential Revision:

GHC Trac Issues: #9252

comment:5 Changed 3 years ago by Edward Z. Yang <ezyang@…>

In a7524eaed33324e2155c47d4a705bef1d70a2b5b/ghc:

Support for multiple signature files in scope.

A common pattern when programming with signatures is to combine multiple
signatures together (signature linking).  We achieve this by making it
not-an-error to have multiple, distinct interface files for the same module
name, as long as they have the same backing implementation.  When a user
imports a module name, they get ALL matching signatures dumped into their

On the way, I refactored the module finder code, which now distinguishes
between exact finds (when you had a 'Module') and regular finds (when
you had a 'ModuleName').  I also refactored the package finder code to
use a Monoid instance on LookupResult to collect together various results.

ToDo: At the moment, if a signature is declared in the local package,
it completely overrides any remote signatures.  Eventually, we'll want
to also pull in the remote signatures (or even override the local signature,
if the full implementation is available.)  There are bunch of ToDos in the
code for what to do once this is done.

ToDo: At the moment, whenever a module name lookup occurs in GHCi and we
would have seen a signature, we instead continue and return the Module
for the backing implementation.  This is correct for most cases, but there
might be some situations where we want something a little more fine-grained
(e.g. :browse should only list identifiers which are available through
the in-scope signatures, and not ALL of them.)

Signed-off-by: Edward Z. Yang <>

Test Plan: validate

Reviewers: simonpj, hvr, austin

Subscribers: carter, thomie

Differential Revision:

GHC Trac Issues: #9252

comment:6 Changed 2 years ago by ezyang

Resolution: fixed
Status: newclosed

comment:7 Changed 2 years ago by ezyang

Owner: ezyang deleted
Resolution: fixed
Status: closednew

comment:8 Changed 2 years ago by ezyang

Resolution: invalid
Status: newclosed

This part of the Backpack design is still in flux, so I'm going to mark this as invalid for now.

comment:9 Changed 2 years ago by Thomas Miedema <thomasmiedema@…>

In 5e66a698dae8c01bcd1a9335346145b32016e119/ghc:

Testsuite: change some expect_fail tests to expect_broken

Change the following tests from expect_fail to expect_broken: and list
the ticket number:

    * driver/sigof03m/sigof03 (#9252)
    * driver/static001 (#8127)
    * partial-sigs/should_compile/EqualityConstraint (#9478)
    * partial-sigs/should_compile/ExtraNumAMROn (#9478)
    * partial-sigs/should_compile/PatBind2 (#9478)
    * partial-sigs/should_fail/TidyClash2 (#9478)
    * simplCore/should_compile/T8832 (#8832)

The following tests are still marked as expect_fail, but it is not
clearly documented why so:

    * gadt/lazypatok
    * indexed-types/should_fail/SkolemOccursLoop

All other expect_fail tests are only expected to fail on either a
certain platform/os or for a certain way only.

Differential Revision:
Note: See TracTickets for help on using tickets.