Opened 4 years ago

Last modified 6 months ago

#10249 new bug

GHCi leaky abstraction: error message mentions `ghciStepIO`

Reported by: Iceland_jack Owned by:
Priority: normal Milestone: 8.2.1
Component: GHCi Version: 7.10.1
Keywords: Cc: hvr
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Incorrect warning at compile-time Test Case: ghci/scripts/T10249
Blocked By: Blocking:
Related Tickets: Differential Rev(s): Phab:D1527, Phab:D1528
Wiki Page:

Description (last modified by bgamari)

$ ghci -fdefer-type-errors -ignore-dot-ghci
GHCi, version 7.10.0.20150316: http://www.haskell.org/ghc/  :? for help
Prelude> _

<interactive>:2:1: Warning:
    Found hole ‘_’ with type: IO t0
    Where: ‘t0’ is an ambiguous type variable
    In the first argument of ‘GHC.GHCi.ghciStepIO ::
                                IO a_aly -> IO a_aly’, namely
      ‘_’
    In a stmt of an interactive GHCi command:
      it <- GHC.GHCi.ghciStepIO :: IO a_aly -> IO a_aly _
*** Exception: <interactive>:2:1:
    Found hole ‘_’ with type: IO t0
    Where: ‘t0’ is an ambiguous type variable
    In the first argument of ‘GHC.GHCi.ghciStepIO ::
                                IO a_aly -> IO a_aly’, namely
      ‘_’
    In a stmt of an interactive GHCi command:
      it <- GHC.GHCi.ghciStepIO :: IO a_aly -> IO a_aly _
(deferred type error)
Prelude> 

It should ideally not expose ghciStepIO to the user.

Change History (12)

comment:1 Changed 4 years ago by simonpj

Yes, that's true. Generally, GHC checks exactly what the user writes, but for GHCi it actually checks a synthesised expression wrapping what the user writes.

This would not be difficult to fix; perhaps a bit fiddly. I'm happy to advise.

Simon

comment:2 Changed 4 years ago by monoidal

For what's worth you don't need deferred type errors to see ghciStepIO; x <- 'a' shows a type error with it as well.

comment:3 Changed 3 years ago by thomie

Summary: Suboptimal error message with deferred type errorsGHCi leaky abstraction: error message mentions `ghciStepIO`
Type: feature requestbug

comment:4 Changed 3 years ago by bgamari

Description: modified (diff)
Milestone: 8.0.1
Type of failure: None/UnknownIncorrect warning at compile-time

comment:5 Changed 3 years ago by thomie

Differential Rev(s): Phab:D1528
Owner: set to thomie
Test Case: ghci/scripts/T10249

comment:6 Changed 3 years ago by thomie

Differential Rev(s): Phab:D1528Phab:D1527, Phab:D1528

comment:7 Changed 3 years ago by Ben Gamari <ben@…>

In 71c0cc15/ghc:

GHCi should not defer typed holes

In the function `tcUserStmt` in compiler/typecheck/TcRnDriver.hs, before
going over the different ways ('plans') to lift an expression typed at
the prompt into the GHCi monad, `Opt_DeferTypeErrors` is disabled. Here is
the accompanying comment:

```
-- Ensure that type errors don't get deferred when type checking the
-- naked expression. Deferring type errors here is unhelpful because the
-- expression gets evaluated right away anyway. It also would potentially
-- emit redundant type-error warnings, one from each plan.
; plan <- unsetGOptM Opt_DeferTypeErrors $
```

Since `Opt_DeferTypeErrors` implies `Opt_DeferTypedHoles`,
`Opt_DeferTypedHoles` should be disabled here as well. This improves
the error message for T10248 (it doesn't mention ghciStepIO anymore).
This is a partial fix for #10249, and a complete fix for #11130.

Depends on D1526

Reviewers: simonpj, austin, bgamari

Reviewed By: simonpj

Subscribers: simonpj

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

GHC Trac Issues: #10249, #11130

comment:8 Changed 3 years ago by bgamari

Milestone: 8.0.18.2.1

This bug won't be fixed in 8.0.1; bumping to 8.2.

comment:9 Changed 2 years ago by bgamari

Resolution: fixed
Status: newclosed

This appears to be fixed however there is no test by the name T10249 (although T10248 is quite related). I've gone ahead and added the test.

comment:10 Changed 2 years ago by Ben Gamari <ben@…>

In 6889400/ghc:

testsuite: Add test for #10249

Test Plan: Validate

Reviewers: austin

Subscribers: thomie

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

GHC Trac Issues: #10249

comment:11 Changed 7 months ago by thomie

Owner: thomie deleted
Resolution: fixed
Status: closednew

The example from comment:2 is not fixed yet:

$ ghci
GHCi, version 8.4.3: http://www.haskell.org/ghc/  :? for help

Prelude> x <- 'a'

<interactive>:1:6: error:
    • Couldn't match expected type ‘IO a0’ with actual type ‘Char’
    • In the first argument of ‘GHC.GHCi.ghciStepIO ::
                                  forall a. IO a -> IO a’, namely
        ‘'a'’
      In a stmt of an interactive GHCi command:
        x <- GHC.GHCi.ghciStepIO :: forall a. IO a -> IO a 'a'

WIP patch here: https://phabricator.haskell.org/D1528

comment:12 Changed 6 months ago by simonpj

Gah. I had a quick look, and it's fiddly. When you write

  a <- e

at the prompt, we get into TcRnDriver.tcUserStmt; in the second equation (i.e. not the BodyStmt case). It does this

       ; let gi_stmt
               | (L loc (BindStmt ty pat expr op1 op2)) <- rn_stmt
                     = L loc $ BindStmt ty pat (nlHsApp ghciStep expr) op1 op2
               | otherwise = rn_stmt

which transforms the Stmt to

  a <- (ghciStepIO :: forall a. M a -> IO a) e

where M is the currently-in-force GHCi monad.

Apparently, via TcRnMonad.getGHCiMonad and setGHCiMonad, it is possible to change the monad in which GHCi bindings are understood, using the library class

module GHC.Ghci where

  class (Monad m) => GHCiSandboxIO m where
    ghciStepIO :: m a -> IO a

to mediate.

I can't see this documented in the user manual, or indeed anywhere else. Sigh.

Anyway it's this ghcStepIO call that the typechecker is complaining about.

I can see various ways to avoid this leakage

  • Typecheck e all by iself, checking that it has type M <something>, before attempting to typecheck a <- ghcStepIO e. This is a bit similar to what happens in "Plan C" of the BodyStmt case of tcUserStmt (see This two-step story is very clunky, alas).
  • Some how avoid adding the error contexts in tcExpr for generated code.

Neither of these seems particularly easy.

Note: See TracTickets for help on using tickets.