Opened 3 years ago

Last modified 4 weeks ago

#11197 new bug

Overeager deferred type errors

Reported by: goldfire Owned by: goldfire
Priority: normal Milestone: 8.8.1
Component: Compiler (Type checker) Version: 7.11
Keywords: TypeInType, DeferredErrors Cc: dfeuer
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:


With TypeInType, the solver now works in terms of unlifted equality. The only place this matters is in deferred type errors, which now are more eager than they were before. For example:

{-# OPTIONS_GHC -fdefer-type-errors #-}

module Main where

main = do
  putStrLn "Hi there."
  putStrLn True

This used to print

Hi there.
Defer: Defer.hs:7:12: error:

Now it prints

Defer: Defer.hs:7:12: error:

No more Hi there..

Thinking about Core, this change should be expected. GHC puts all evidence bindings for main at the top, and with unlifted equality in the solver, these bindings now contain case typeError ... of ..., which forces the type error eagerly. Previously, there was a lazy binding for a lifted equality witness, unpacked only at the last moment by magic in the desugarer, thus the lazier warning.

Simon has proposed customizing the FloatIn pass to deal with this scenario. I do believe this would work nicely, but I have not yet implemented it.

Change History (19)

comment:1 Changed 3 years ago by goldfire

This regression affects test cases Defer02 and T7861. I'm less concerned about the latter, as it requires ImpredicativeTypes.

comment:2 Changed 3 years ago by Richard Eisenberg <eir@…>

In 67465497/ghc:

Add kind equalities to GHC.

This implements the ideas originally put forward in
"System FC with Explicit Kind Equality" (ICFP'13).

There are several noteworthy changes with this patch:
 * We now have casts in types. These change the kind
   of a type. See new constructor `CastTy`.

 * All types and all constructors can be promoted.
   This includes GADT constructors. GADT pattern matches
   take place in type family equations. In Core,
   types can now be applied to coercions via the
   `CoercionTy` constructor.

 * Coercions can now be heterogeneous, relating types
   of different kinds. A coercion proving `t1 :: k1 ~ t2 :: k2`
   proves both that `t1` and `t2` are the same and also that
   `k1` and `k2` are the same.

 * The `Coercion` type has been significantly enhanced.
   The documentation in `docs/core-spec/core-spec.pdf` reflects
   the new reality.

 * The type of `*` is now `*`. No more `BOX`.

 * Users can write explicit kind variables in their code,
   anywhere they can write type variables. For backward compatibility,
   automatic inference of kind-variable binding is still permitted.

 * The new extension `TypeInType` turns on the new user-facing

 * Type families and synonyms are now promoted to kinds. This causes
   trouble with parsing `*`, leading to the somewhat awkward new
   `HsAppsTy` constructor for `HsType`. This is dispatched with in
   the renamer, where the kind `*` can be told apart from a
   type-level multiplication operator. Without `-XTypeInType` the
   old behavior persists. With `-XTypeInType`, you need to import
   `Data.Kind` to get `*`, also known as `Type`.

 * The kind-checking algorithms in TcHsType have been significantly
   rewritten to allow for enhanced kinds.

 * The new features are still quite experimental and may be in flux.

 * TODO: Several open tickets: #11195, #11196, #11197, #11198, #11203.

 * TODO: Update user manual.

Tickets addressed: #9017, #9173, #7961, #10524, #8566, #11142.
Updates Haddock submodule.

comment:3 Changed 3 years ago by simonpj

Keywords: TypeInType added

comment:4 Changed 2 years ago by goldfire

See also #2988, which discusses other improvements to floating-in.

comment:5 Changed 2 years ago by thomie

Component: CompilerCompiler (Type checker)

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

In aa61174/ghc:

users-guide: Add references to various issues in bugs section

Test Plan: Read it

Reviewers: austin

Reviewed By: austin

Subscribers: thomie

Differential Revision:

GHC Trac Issues: #7411, #11197, #11554, #11715

comment:7 Changed 2 years ago by thoughtpolice


comment:8 Changed 2 years ago by bgamari

It looks like this is already affecting users:

comment:9 Changed 2 years ago by goldfire

The commentary on the PR linked to in comment:8 contains a workaround in that case.

comment:10 Changed 23 months ago by bgamari


This won't happen for 8.0.2.

comment:11 Changed 16 months ago by bgamari


Given that 8.2.1-rc1 is imminent, I'm bumping these off to the 8.4

comment:12 Changed 6 months ago by bgamari


This ticket won't be resolved in 8.4; remilestoning for 8.6. Do holler if you are affected by this or would otherwise like to work on it.

comment:13 Changed 2 months ago by sighingnow

When -fdefer-type-errors is enabled, the program

main = do
  putStrLn "Hi there."
  putStrLn 1

works well. However the program

main = do
  putStrLn "Hi there."
  putStrLn True

emits the deferred type error message eagerly and doesn't execute putStrLn "Hi there.".

In the first case, the type error is EvVarDest evar:

Wanted = WC {wc_simple = [WD] $dNum_a1zB {0}:: Num String (CDictCan(psc))}

However in the second case, the type error is HoleDest hole:

Wanted = WC {wc_simple = [WD] hole{co_a1zO} {0}:: (Bool :: *) GHC.Prim.~# ([Char] :: *)}

Seems that the coercion hole is placed at wrong place. This ticket may related to Trac #14584.

comment:14 Changed 2 months ago by simonpj

Here's what is happening. In the former case we get

  = let {
      $dNum_a1d8 :: Num String
      $dNum_a1d8 = Control.Exception.Base.typeError
                      @ 'GHC.Types.LiftedRep @ (Num String) "blah blah blah
    } in
    let {
      $dMonad_axl :: Monad IO
      $dMonad_axl = GHC.Base.$fMonadIO } in
    letrec {
      main_a1da :: IO ()
        = >>
            @ IO
            @ ()
            @ ()
            (putStrLn (GHC.CString.unpackCString# "Hi there."#))
            (putStrLn (fromInteger @ String $dNum_a1d8 1)); } in

and the binding for dNum_a1d8 can float inwards/be inlined. In the latter case we get

  = case Control.Exception.Base.typeError
           @ ('GHC.Types.TupleRep '[])
           @ ((Bool :: *) GHC.Prim.~# ([Char] :: *))
           "blah blah blah"
    of co_a11b
    { __DEFAULT ->
      @ IO
      @ ()
      @ ()
      (putStrLn (GHC.CString.unpackCString# "Hi there."#))
          `cast` (Sub co_a11b :: (Bool :: *) ~R# ([Char] :: *))))

and the simplifier does not float in arbitrary case-expressions, for fear of changing error/termination behaviour.

What do to? All I can think of is to make a special case for coercions, and be willing to float them in, on the grounds that evidence bindings are added by the compiler and should have as narrow scope as possible. Any objections?

comment:15 Changed 8 weeks ago by simonpj

Keywords: DeferredErrors added

comment:16 Changed 8 weeks ago by dfeuer

Does -fdefer-type-errors pull its weight as a compiler feature? The package mentioned above (should-not-typecheck) could arguably be improved by using GHCi instead. I think it makes sense to at least consider the alternative of ripping out the feature instead of jumping through hoops to fix it. It strikes me as complicated, intrusive, and (to my mind) not very useful. But it would be nice to hear whether people find it useful for writing programs or for teaching Haskell to beginners.

comment:17 Changed 8 weeks ago by dfeuer

Cc: dfeuer added

comment:18 Changed 8 weeks ago by simonpj

Yes, I'd be very interested to know how useful people find -fdefer-type-errors.

But in fact it's extraordinarily simple to implement, albeit with some wrinkles around the edges like this ticket.

comment:19 Changed 4 weeks ago by bgamari


These won't be fixed for 8.6, bumping to 8.8.

Note: See TracTickets for help on using tickets.