[GHC] #11176: Typechecked AST for recursive top-level call refers to non-exported HsVar.

GHC ghc-devs at haskell.org
Tue Dec 8 12:31:18 UTC 2015


#11176: Typechecked AST for recursive top-level call refers to non-exported HsVar.
-------------------------------------+-------------------------------------
        Reporter:  literon           |                Owner:
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:
       Component:  Compiler          |              Version:  7.10.2
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by simonpj):

 I'm surprised that `n_sort` is `WiredIn` for `aaa`.  That is most
 peculiar.

 Did you read `Note [AbsBinds]` in `HsBinds`?
 {{{
 Note [AbsBinds]
 ~~~~~~~~~~~~~~~
 The AbsBinds constructor is used in the output of the type checker, to
 record
 *typechecked* and *generalised* bindings.  Consider a module M, with this
 top-level binding
     M.reverse []     = []
     M.reverse (x:xs) = M.reverse xs ++ [x]

 In Hindley-Milner, a recursive binding is typechecked with the *recursive*
 uses
 being *monomorphic*.  So after typechecking *and* desugaring we will get
 something
 like this

     M.reverse :: forall a. [a] -> [a]
       = /\a. letrec
                 reverse :: [a] -> [a] = \xs -> case xs of
                                                 []     -> []
                                                 (x:xs) -> reverse xs ++
 [x]
              in reverse

 Notice that 'M.reverse' is polymorphic as expected, but there is a local
 definition for plain 'reverse' which is *monomorphic*.  The type variable
 'a' scopes over the entire letrec.

 That's after desugaring.  What about after type checking but before
 desugaring?
 That's where AbsBinds comes in.  It looks like this:

    AbsBinds { abs_tvs     = [a]
             , abs_exports = [ABE { abe_poly = M.reverse :: forall a. [a]
 -> [a],
                                  , abe_mono = reverse :: [a] -> [a]}]
             , abs_binds = { reverse :: [a] -> [a]
                                = \xs -> case xs of
                                             []     -> []
                                             (x:xs) -> reverse xs ++ [x] }
 }

 Here,
   * abs_tvs says what type variables are abstracted over the binding
 group,
     just 'a' in this case.
   * abs_binds is the *monomorphic* bindings of the group
   * abs_exports describes how to get the polymorphic Id 'M.reverse' from
 the
     monomorphic one 'reverse'

 Notice that the *original* function (the polymorphic one you thought
 you were defining) appears in the abe_poly field of the
 abs_exports. The bindings in abs_binds are for fresh, local, Ids with
 a *monomorphic* Id.

 If there is a group of mutually recursive functions without type
 signatures, we get one AbsBinds with the monomorphic versions of the
 bindings in abs_binds, and one element of abe_exports for each
 variable bound in the mutually recursive group.  This is true even for
 pattern bindings.  Example:
         (f,g) = (\x -> x, f)
 After type checking we get
    AbsBinds { abs_tvs     = [a]
             , abs_exports = [ ABE { abe_poly = M.f :: forall a. a -> a
                                   , abe_mono = f :: a -> a }
                             , ABE { abe_poly = M.g :: forall a. a -> a
                                   , abe_mono = g :: a -> a }]
             , abs_binds = { (f,g) = (\x -> x, f) }
 }}}
 If it's not clear enough I should rewrite it until it is.

 So yes, there's a fundamental reason.

 The rule is this: a reference on the RHS goes to the monomorphic version
 (`abe_mono`) iff

 * The variable, say 'x', has no type signature
 * The RHS is part of a mutually recursive group which binds 'x'.

 To find mutually recursive groups, perform a strongly-connnected-component
 analysis on the bindings, where there is a an edge from binding `y = ey`
 to `x = ex` iff

 * `ey` mentions `x`
 * `x` does not have a type signature

 Does that help?  How could the Note be better?

 Simon

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


More information about the ghc-tickets mailing list