[GHC] #11371: Bogus in-scope set in substitutions

GHC ghc-devs at haskell.org
Mon Jan 18 12:43:17 UTC 2016


#11371: Bogus in-scope set in substitutions
-------------------------------------+-------------------------------------
        Reporter:  simonpj           |                Owner:  niteria
            Type:  bug               |               Status:  new
        Priority:  high              |            Milestone:  8.2.1
       Component:  Compiler          |              Version:  7.10.3
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:  #11360            |  Differential Rev(s):  phab:D1792
       Wiki Page:                    |
-------------------------------------+-------------------------------------
Description changed by simonpj:

Old description:

> Bartosz [https://mail.haskell.org/pipermail/ghc-
> devs/2016-January/010892.html reports] that substitution isn't working
> properly for him.  He cites this Note in `TyCoRep`:
> {{{
> -- Note [Generating the in-scope set for a substitution]
> -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> -- If we want to substitute [a -> ty1, b -> ty2] I used to
> -- think it was enough to generate an in-scope set that includes
> -- fv(ty1,ty2).  But that's not enough; we really should also take the
> -- free vars of the type we are substituting into!  Example:
> --      (forall b. (a,b,x)) [a -> List b]
> -- Then if we use the in-scope set {b}, there is a danger we will rename
> -- the forall'd variable to 'x' by mistake, getting this:
> --      (forall x. (List b, x, x))
> -- Urk!  This means looking at all the calls to mkOpenTCvSubst....
> }}}
> I think this is an outright bug that has been lurking for ages, and which
> Bartosz has just managed to tickle.
>
> Things to do:
>
> * We should add an ASSERT to substTy (and similar functions): **when
> calling `substTy subst ty` it should be the case that the in-scope set in
> the substitution is a superset of**
>   * **The free vars of the range of the substitution**
>   * **The free vars of ty minus the domain of the substitution**
>
>   That ASSERT could be added to the immediate callers of `subst_ty` in
> `TyCoRep`.
>
>   (Bartosz: if you add that you should find that it trips before the bug
> you are actually getting.)
>
> * How to fix it properly?  The places to look are: everywhere that uses
> (transitively) one of the `mkOpenTCvSubst` or `zipOpenTCvSubst`
> functions.
>   * Many calls to `mkOpenTCvSubst` produce a substitution that is only
> applied to closed types; or at least to types whose only free variables
> are the ones in the domain of the substitution.  Example: the call to
> `zipOpenTCvSubst` in `DataCon.dataConInstSig`.  These ones will all
> satisfy the ASSERT[[BR]][[BR]]
>   * In other cases, we already have the in-scope set in hand.  Example:
> in `CoreLint.lintTyApp` we find a call to `substTyWith`.  But Lint
> carries an in-scope set, so it would be easy to pass it to
> `substTyWith`.[[BR]][[BR]]
>   * Finally there may be cases where we really have to take the free vars
> of the type we are substituting into, and add them to the in-scope set.
>
> Doubtless all this applies to substituting in coercions too, and indeed
> into expressions.

New description:

 Bartosz [https://mail.haskell.org/pipermail/ghc-
 devs/2016-January/010892.html reports] that substitution isn't working
 properly for him.  He cites this Note in `TyCoRep`:
 {{{
 -- Note [Generating the in-scope set for a substitution]
 -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 -- If we want to substitute [a -> ty1, b -> ty2] I used to
 -- think it was enough to generate an in-scope set that includes
 -- fv(ty1,ty2).  But that's not enough; we really should also take the
 -- free vars of the type we are substituting into!  Example:
 --      (forall b. (a,b,x)) [a -> List b]
 -- Then if we use the in-scope set {b}, there is a danger we will rename
 -- the forall'd variable to 'x' by mistake, getting this:
 --      (forall x. (List b, x, x))
 -- Urk!  This means looking at all the calls to mkOpenTCvSubst....
 }}}
 I think this is an outright bug that has been lurking for ages, and which
 Bartosz has just managed to tickle.

 Things to do:

 * We should add an ASSERT to substTy (and similar functions): **when
 calling `substTy subst ty` it should be the case that the in-scope set in
 the substitution is a superset of both**
   * **The free vars of the range of the substitution**
   * **The free vars of ty minus the domain of the substitution**

   That ASSERT could be added to the immediate callers of `subst_ty` in
 `TyCoRep`.

   (Bartosz: if you add that you should find that it trips before the bug
 you are actually getting.)

 * How to fix it properly?  The places to look are: everywhere that uses
 (transitively) one of the `mkOpenTCvSubst` or `zipOpenTCvSubst` functions.
   * Many calls to `mkOpenTCvSubst` produce a substitution that is only
 applied to closed types; or at least to types whose only free variables
 are the ones in the domain of the substitution.  Example: the call to
 `zipOpenTCvSubst` in `DataCon.dataConInstSig`.  These ones will all
 satisfy the ASSERT[[BR]][[BR]]
   * In other cases, we already have the in-scope set in hand.  Example: in
 `CoreLint.lintTyApp` we find a call to `substTyWith`.  But Lint carries an
 in-scope set, so it would be easy to pass it to `substTyWith`.[[BR]][[BR]]
   * Finally there may be cases where we really have to take the free vars
 of the type we are substituting into, and add them to the in-scope set.

 Doubtless all this applies to substituting in coercions too, and indeed
 into expressions.

--

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


More information about the ghc-tickets mailing list