[GHC] #15286: "Can't use Natural in base" when compiling GHC.Natural with -O0

GHC ghc-devs at haskell.org
Thu Feb 7 13:04:05 UTC 2019


#15286: "Can't use Natural in base" when compiling GHC.Natural with -O0
-------------------------------------+-------------------------------------
        Reporter:  alpmestan         |                Owner:  (none)
            Type:  bug               |               Status:  patch
        Priority:  normal            |            Milestone:
       Component:  libraries/base    |              Version:  8.5
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  Building GHC      |  Unknown/Multiple
  failed                             |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):  Phab:D4880
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by hsyl20):

 The current handling of "wired-in" things such as Integer or Natural is
 very fragile. In your case, as you use type-level nats, GHC implicitly
 needs `Natural` from `GHC.Natural` but it can't access it because
 `GHC.Natural` is also defined in `base`. In `coreSyn/CorePrep.hs` we
 explicitly detect use of Natural when we compile `base` (see
 `guardNaturalUse`) to generate the panic you get. Otherwise GHC would fail
 with something like a "can't find/load interface" error.

 Not allowing to depend on `Natural` in `base` is annoying/stupid. In the
 past I've tried the most obvious solution: put `GHC.Natural` in its own
 package just like we do for `integer-*`. However it's harder for Natural
 than it is for Integer because `GHC.Natural` uses `Exception` (with an
 import cycle) and `Maybe` which are defined in `base`...

 I have written a note to state the problem and some ideas:

 {{{
 GHC has some built-in functions, types, constructors, etc.. These are not
 defined in Haskell and when it encounters them it knows what to do with
 them.

 GHC also knows some Haskell defined functions, types, constructors, etc.
 It can
 use this knowledge to perform code transformation (e.g. constant folding)
 and to
 generate some code (e.g. desugaring lists, deriving instances, etc.).

 In this latter case, GHC has to build the Haskell code defining these
 functions,
 types, constructors, etc. without assuming knowledge of non already built
 Haskell code. For instance, suppose `Integer` data type and functions are
 defined in the "GHC.Integer" module. When building "GHC.Integer" GHC must
 assume
 that it knows nothing about Integer (nor about anything that depends on
 knowing
 Integer).

 It can be tricky: suppose we are building the Dummy module defined as
 follow:

    {-# LANGUAGE NoImplicitPrelude #-}
    module Dummy where
       dummy = 0

 Even if Dummy doesn't depend on anything, GHC will default the type of
 "dummy"
 to Integer! So when building this module, there is an implicit dependency
 on
 knowing Integer and GHC.Integer must have been built already for GHC to
 query
 some stuff from it. In this case we could change the default or fix the
 type to
 avoid the dependency or to make it explicit:

    {-# LANGUAGE NoImplicitPrelude #-}
    module Dummy where
       default (Int)
       -- or: dummy :: Int
       -- or: import GHC.Integer ()
       dummy = 0


 At the time of writing, these dependencies are manually handled this way
 (in
 base, etc.) This is very fragile (see #15286).

 -------------

 Ideas:

 1) we should automatically detect implicit dependencies: when GHC is about
 to
 use a builtin Name or Id, it should:
    - detect the dependency it comes from
    - detect cyclic dependencies with the current module
    - ensure the dependency is built
    - clearly indicate why it can't build the implicit dependency if it
 happens

 Shouldn't be too hard: GHC should pretend the module contains an implicit
 "import" when it is about to use a builtin. GHC could even "source import"
 dependencies when there is a cycle because it would mean we compile the
 package
 containing both modules.

 A minor issue is that this implicit import could appear quite late in the
 compilation pipeline (during desugaring, deriving, maybe codegen, etc.):
 GHC
 could have to switch from building the current module to build the
 dependencies
 or fail and indicate to the caller the dependencies to build beforehand.
 The
 latter would be relatively slow because GHC would need to start compiling
 the
 module again and may fail the same way further in the compilation pipeline
 until
 all dependencies are built.

 2) GHC shouldn't assume knowledge of unit IDs. We should be able to
 disable
 whole builtin stuff at once.

 E.g. when building integer-* packages, GHC uses predefined unit-id with
 the
 parameter: -this-unit-id integer-wired-in

 We should avoid this: instead GHC should query the unit-id of the
 integer-*
 package somehow (or use one given on the command line to allow easy switch
 between integer packages). We should also allow the possibility of
 compiling
 without integer-* package at all: this is what is implicitly assumed by
 GHC when
 it builds ghc-prim and integer-* packages (see `guardIntegerUse` in
 coreSyn/CorePrep.hs).

 Instead of relying on knowing two blessed integer-* packages, GHC could
 detect
 the presence of constructors such as "S#" in the given integer package so
 to use
 rules and generate code accordingly. It would make trying new
 releases/implementations of those much easier.

 Same for other packages (natural, base, template-haskell, etc.). E.g. we
 should
 be able to disable template-haskell, etc. When some dependencies are
 disabled/missing, GHC can't produce code using them nor use builtin rules
 assuming it knows them.
 }}}

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15286#comment:9>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list