Opened 18 months ago

Last modified 16 months ago

#15016 new bug

Referencing a do-bound variable in a rec block with ApplicativeDo results in variable not in scope during type checking

Reported by: rjmk Owned by: simonmar
Priority: high Milestone: 8.4.3
Component: Compiler Version: 8.2.2
Keywords: ApplicativeDo Cc: simonmar
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

I searched + hope this isn't a dupe.

When using both ApplicativeDo and RecursiveDo, referring to a do-bound variable from outside of a rec block causes a GHC internal error.

Here's a minimal example:

{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE RecursiveDo #-}

module Lib where

import Control.Monad.Fix

f :: MonadFix m => m ()
f = do
  a <- return ()
  rec
    let b = a
  return ()

The error message I get is

src/Lib.hs:12:13: error:
    • GHC internal error: ‘a’ is not in scope during type checking, but it passed the renamer
      tcl_env of environment: [a1pF :-> Type variable ‘m’ = m :: * -> *,
                               r1mX :-> Identifier[f::forall (m :: * -> *).
                                                      MonadFix m =>
                                                      m (), TopLevelLet [] True]]
    • In the expression: a
      In an equation for ‘b’: b = a
      In a stmt of a 'do' block: rec let b = a
   |
12 |     let b = a
   |             ^

I have reproduced it in 8.2.2 and 8.4.1

Change History (7)

comment:1 Changed 18 months ago by sighingnow

Owner: set to sighingnow

I think the "not is scope" is by design. See more discussion under ticket:4148. When we use rec in do blocks, rather than mdo blocks, the outer variables won't be included into the scope of rec block.

The real problem is when there's no binding for a inside rec block, the rhs a in let b = a will have the same name with the outer a.

For code:

The rename produces:

Lib.f :: MonadFix m_auv => m_auv ()
Lib.f
  = do a_auw <- return () |
       () <- do rec let b_aux = a_auw
                return ()
       return ()

But for code:

f :: MonadFix m => m ()
f = do
  a <- return ()
  rec
    let b = a
        a = ()
  return ()

The rename produces:

Lib.f :: MonadFix m_auv => m_auv ()
Lib.f
  = do a_auw <- return () |
       () <- do rec let b_aux = a_auy
                        a_auy = ()
                return ()
       return ()

Indeed it's a bug. I'm optimistic to assign that to myself :) We also should note this behavior of rec in documentation.

comment:2 Changed 18 months ago by rjmk

I'm not sure I understand you correctly when you say

When we use rec in do blocks, rather than mdo blocks, the outer variables won't be included into the scope of rec block.

so this may not be relevant, but removing the ApplicativeDo allows the code to compile.

comment:3 Changed 18 months ago by sighingnow

I think the code in the description shouldn't be accept even without ApplicativeDo extension.

Waiting for experts in this area to comment.

comment:4 Changed 17 months ago by simonpj

Owner: changed from sighingnow to simonmar
Priority: normalhigh

Simon, might you take a look? GHC should never crash.

comment:5 Changed 17 months ago by sighingnow

Indeed it's not a crash, it's just an ordinary error message with description "GHC internal error:". The error is reported in noFound method in TcEnv.hs.

           _ -> failWithTc $
                vcat[text "GHC internal error:" <+> quotes (ppr name) <+>

comment:6 Changed 17 months ago by simonpj

Maybe so, but it still should never happen!

comment:7 Changed 16 months ago by simonmar

Cc: simonmar added
Keywords: ApplicativeDo added
Note: See TracTickets for help on using tickets.