Sebastian Graf pushed to branch wip/T17833 at Glasgow Haskell Compiler / GHC

Commits:

2 changed files:

Changes:

  • compiler/GHC/Core/Opt/Simplify.hs
    ... ... @@ -14,6 +14,7 @@ import GHC.Core.Rules
    14 14
     import GHC.Core.Ppr     ( pprCoreBindings, pprCoreExpr )
    
    15 15
     import GHC.Core.Opt.OccurAnal ( occurAnalysePgm, occurAnalyseExpr )
    
    16 16
     import GHC.Core.Stats   ( coreBindsSize, coreBindsStats, exprSize )
    
    17
    +import GHC.Core.FVs     ( exprFreeVars )
    
    17 18
     import GHC.Core.Utils   ( mkTicks, stripTicksTop )
    
    18 19
     import GHC.Core.Lint    ( LintPassResultConfig, dumpPassResult, lintPassResult )
    
    19 20
     import GHC.Core.Opt.Simplify.Iteration ( simplTopBinds, simplExpr, simplImpRules )
    
    ... ... @@ -74,7 +75,10 @@ simplifyExpr logger euc opts expr
    74 75
             ; let fam_envs = ( eps_fam_inst_env eps
    
    75 76
                              , extendFamInstEnvList emptyFamInstEnv $ se_fam_inst opts
    
    76 77
                              )
    
    77
    -              simpl_env = mkSimplEnv (se_mode opts) fam_envs
    
    78
    +              -- See Note [Seed the in-scope set for open expressions]
    
    79
    +              simpl_env = setInScopeSet base_env
    
    80
    +                            (getInScope base_env `extendInScopeSetSet` exprFreeVars expr)
    
    81
    +              base_env  = mkSimplEnv (se_mode opts) fam_envs
    
    78 82
                   top_env_cfg = se_top_env_cfg opts
    
    79 83
                   read_eps_rules = eps_rule_base <$> eucEPS euc
    
    80 84
                   read_ruleenv = updExternalPackageRules emptyRuleEnv <$> read_eps_rules
    
    ... ... @@ -94,6 +98,49 @@ simplifyExpr logger euc opts expr
    94 98
             ; return expr'
    
    95 99
             }
    
    96 100
     
    
    101
    +{- Note [Seed the in-scope set for open expressions]
    
    102
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    103
    +An invariant of the Simplifier is that the in-scope set contains all the free
    
    104
    +variables of the expression being simplified.  Why?  So that the Simplifier
    
    105
    +never invents a "fresh" binder that accidentally captures one of those free
    
    106
    +variables.
    
    107
    +
    
    108
    +'simplifyExpr' establishes that invariant by initialising the in-scope set with
    
    109
    +the free variables of the expression it is given.  For a closed expression this
    
    110
    +adds nothing.
    
    111
    +
    
    112
    +But how can 'simplifyExpr' be handed an /open/ expression in the first place?
    
    113
    +The whole-module pipeline never does so: 'simplifyPgm' only ever simplifies
    
    114
    +closed bindings.  The one caller that can is 'hscCompileCoreExpr' (in
    
    115
    +GHC.Driver.Main.Passes), which compiles a single Core expression, and is itself
    
    116
    +reached from just two places:
    
    117
    +
    
    118
    +  * GHCi, for an expression typed at the prompt, and in particular in the
    
    119
    +    debugger (see below);
    
    120
    +  * Template Haskell, when running a splice (see GHC.Tc.Gen.Splice).
    
    121
    +
    
    122
    +So this is never on the critical path for mainstream compilation.
    
    123
    +
    
    124
    +Here is how the debugger hands us an open expression (test break006).  We are
    
    125
    +stopped at a breakpoint in
    
    126
    +    mymap f (x:xs) = f x : ...
    
    127
    +where the debugger knows that 'x :: Int' but not yet the result type of 'f'.  So
    
    128
    +it invents a RuntimeUnk skolem 'a' and gives 'f :: Int -> a'.  The user then
    
    129
    +types
    
    130
    +    let y = f x
    
    131
    +GHCi type-checks that and, to hand the result back to the interpreter (see
    
    132
    +GHC.Tc.Module.tcGhciStmts), wraps it as
    
    133
    +    returnIO @[Any] [unsafeCoerce# @LiftedRep @LiftedRep @a @Any y]
    
    134
    +in which the skolem 'a' is free.
    
    135
    +
    
    136
    +When the Simplifier instantiates that 'unsafeCoerce#', it builds a substitution
    
    137
    +mapping unsafeCoerce#'s quantified type variables to (LiftedRep, LiftedRep, a,
    
    138
    +Any), whose range therefore mentions 'a'.  The in-scope set of a substitution
    
    139
    +must contain the free variables of its range (see Note [The substitution
    
    140
    +invariant] in GHC.Core.TyCo.Subst).  Without the seeding above that invariant is
    
    141
    +broken, and in a compiler built with assertions substTy's sanity check fails
    
    142
    +(#17833, and its duplicate #21118). -}
    
    143
    +
    
    97 144
     simplExprGently :: SimplEnv -> CoreExpr -> SimplM CoreExpr
    
    98 145
     -- ^ Simplifies an expression by doing occurrence analysis, then simplification,
    
    99 146
     -- and repeating (twice currently), because one pass alone leaves tons of crud.
    

  • testsuite/tests/ghci.debugger/scripts/all.T
    ... ... @@ -52,8 +52,7 @@ test('break002', extra_files(['../Test2.hs']), ghci_script, ['break002.script'])
    52 52
     test('break003', extra_files(['../Test3.hs']), ghci_script, ['break003.script'])
    
    53 53
     test('break005', extra_files(['../QSort.hs']), ghci_script, ['break005.script'])
    
    54 54
     test('break006',
    
    55
    -     [ when(compiler_debugged(), expect_broken(17833)),
    
    56
    -       extra_files(['../Test3.hs'])],
    
    55
    +     [extra_files(['../Test3.hs'])],
    
    57 56
          ghci_script,
    
    58 57
          ['break006.script'])
    
    59 58
     test('break007', extra_files(['Break007.hs']), ghci_script, ['break007.script'])