Skip to content

Exitification abstracts over shadowed variables

Simon did some code review of Exitify.hs in #14152 (closed)##15110 (closed) and he was onto something; the code is wrong after all:

Consider this core term

  joinrec j (x :: Bool) (x :: Int) =
    if x == 0
    then foo x
    else jump j True (x - 1)
  in …

where the two parameters x and x are different variables, but shadow each other (i.e. have the same unique). This is legal Core!

But Exitification chooses the variables to abstract over in this line:

        -- The possible arguments of this exit join point
        -- No need for `sortQuantVars`, `captured` is already in dependency order
        abs_vars = map zap $ filter (`elemVarSet` fvs) captured

where captured = [x::Bool,x::Int] in this case, which would yield this code

  join exit (x :: Bool) (x :: Int) = foo x in
  joinrec j (x :: Bool) (x :: Int) =
    if x == 0
    then jump exit (x::Bool) (x::Int)
    else jump j True (x - 1)
  in …

which is no longer type correct (or even “scope-correct”) any more, as it passes the Int-typed x as the Bool argument to exit.

The conditions where this happens, i.e. such shadowing, is rather obscure so I did not even try to produce a lint error here. It also means that this is rather low severity, but I’ll still go and fix it.

An application of reverseNub seems to be in order – or simply switching to keeping captured in a DVarSet rather than a list (in which case sortQuantVars would be required…)

Trac metadata
Trac field Value
Version 8.5
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information