Opened 18 months ago

Closed 17 months ago

Last modified 17 months ago

#15012 closed bug (fixed)

"Iface type variable out of scope" when compiling with -c

Reported by: RyanGlScott Owned by:
Priority: normal Milestone: 8.6.1
Component: Compiler Version: 8.4.1
Keywords: deriving Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: GHC rejects valid program Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s): Phab:D4602
Wiki Page:

Description

Take these two files:

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeFamilies #-}
module Foo where

import GHC.Generics

type FakeOut a = Int

data family   TyFamily y z
data instance TyFamily a b = TyFamily Int (FakeOut b)
  deriving Generic1
module Bar where

import Foo
import GHC.Generics

main :: IO ()
main = print $ from1 $ TyFamily 1 2

And compile them like so:

$ ghc -c Foo.hs
$ ghc -c Bar.hs
./Foo.hi
Declaration for Rep1_R:TyFamilyab
Axiom branches Rep1_R:TyFamilyab:
  Iface type variable out of scope:  b
Cannot continue after interface file error

I can reproduce this with every version of GHC from 7.8.4 onward, so this is quite an old bug!

Change History (6)

comment:1 Changed 18 months ago by RyanGlScott

Keywords: deriving added

I suspect that DeriveGeneric is to blame here. Here is what -ddump-deriv tells us about the derived Rep1 associated type family instance for Generic1:

Derived type family instances:
  type GHC.Generics.Rep1 (Foo.TyFamily a_a2ta) = GHC.Generics.D1
                                                   ('GHC.Generics.MetaData
                                                      "TyFamily" "Foo" "main" 'GHC.Types.False)
                                                   (GHC.Generics.C1
                                                      ('GHC.Generics.MetaCons
                                                         "TyFamily"
                                                         'GHC.Generics.PrefixI
                                                         'GHC.Types.False)
                                                      (GHC.Generics.S1
                                                         ('GHC.Generics.MetaSel
                                                            'GHC.Base.Nothing
                                                            'GHC.Generics.NoSourceUnpackedness
                                                            'GHC.Generics.NoSourceStrictness
                                                            'GHC.Generics.DecidedLazy)
                                                         (GHC.Generics.Rec0 GHC.Types.Int)
                                                       GHC.Generics.:*: GHC.Generics.S1
                                                                          ('GHC.Generics.MetaSel
                                                                             'GHC.Base.Nothing
                                                                             'GHC.Generics.NoSourceUnpackedness
                                                                             'GHC.Generics.NoSourceStrictness
                                                                             'GHC.Generics.DecidedLazy)
                                                                          (GHC.Generics.Rec0
                                                                             (Foo.FakeOut b_a2q1))))

Notice that b_a2q1 is unbound in this definition! Perhaps we should be turning this into Any?

comment:2 Changed 17 months ago by RyanGlScott

Differential Rev(s): Phab:D4602
Status: newpatch

comment:3 Changed 17 months ago by simonpj

I added a suggestion on the Phab, but it is (still, alas) not broadcast.

comment:4 Changed 17 months ago by Ben Gamari <ben@…>

In b08a6d75/ghc:

Fix #15012 with a well-placed use of Any

Previously, derived `Generic1` instances could have associated `Rep1`
type family instances with unbound variables, such as in the following
example:

```lang=haskell
data T a = MkT (FakeOut a) deriving Generic1
type FakeOut a = Int

==>

instance Generic1 T where
  type Rep1 T = ... (Rec0 (FakeOut a))
```

Yikes! To avoid this, we simply map the last type variable in a
derived `Generic1` instance to `Any`.

Test Plan: make test TEST=T15012

Reviewers: bgamari

Reviewed By: bgamari

Subscribers: simonpj, thomie, carter

GHC Trac Issues: #15012

Differential Revision: https://phabricator.haskell.org/D4602

comment:5 Changed 17 months ago by bgamari

Resolution: fixed
Status: patchclosed

comment:6 Changed 17 months ago by Ben Gamari <ben@…>

In 257c13d8/ghc:

Lint types in newFamInst

We weren't linting the types used in `newFamInst`, which
might have been why #15012 went undiscovered for so long. Let's fix
that.

One has to be surprisingly careful with expanding type synonyms in
`lintType`, since in the offending program (simplified):

```lang=haskell
type FakeOut a = Int

type family TF a
type instance TF Int = FakeOut a
```

If one expands type synonyms, then `FakeOut a` will expand to
`Int`, which masks the issue (that `a` is unbound). I added an
extra Lint flag to configure whether type synonyms should be
expanded or not in Lint, and disabled this when calling `lintTypes`
from `newFamInst`.

As evidence that this works, I ran it on the offending program
from #15012, and voilà:

```
$ ghc3/inplace/bin/ghc-stage2 Bug.hs -dcore-lint
[1 of 1] Compiling Foo              ( Bug.hs, Bug.o )
ghc-stage2: panic! (the 'impossible' happened)
  (GHC version 8.5.20180417 for x86_64-unknown-linux):
        Core Lint error
  <no location info>: warning:
      In the type ‘... (Rec0 (FakeOut b_a1Qt))))’
      @ b_a1Qt is out of scope
```

Test Plan: make test TEST=T15057

Reviewers: simonpj, goldfire, bgamari

Reviewed By: bgamari

Subscribers: thomie, carter

GHC Trac Issues: #15057

Differential Revision: https://phabricator.haskell.org/D4611
Note: See TracTickets for help on using tickets.