[GHC] #10875: Unexpected defaulting of partial type signatures and inconsistent behaviour when -fdefer-typed-holes is set.

GHC ghc-devs at haskell.org
Sun Sep 13 20:47:09 UTC 2015


#10875: Unexpected defaulting of partial type signatures and inconsistent behaviour
when -fdefer-typed-holes is set.
-------------------------------------+-------------------------------------
        Reporter:  holzensp          |                   Owner:
            Type:  bug               |                  Status:  new
        Priority:  normal            |               Milestone:
       Component:  Compiler          |                 Version:  7.10.2
      Resolution:                    |                Keywords:
                                     |  PartialTypeSignatures TypedHoles
Operating System:  MacOS X           |            Architecture:  x86_64
 Type of failure:  Incorrect         |  (amd64)
  warning at compile-time            |               Test Case:
      Blocked By:                    |                Blocking:
 Related Tickets:                    |  Differential Revisions:
-------------------------------------+-------------------------------------
Description changed by holzensp:

Old description:

> Maybe this should be one bug report and one feature request, but for now,
> I'll report them together. Consider the following program:
> {{{#!hs
> {-#LANGUAGE PartialTypeSignatures #-}
> {-#LANGUAGE NamedWildCards #-}
> {-#LANGUAGE NoMonomorphismRestriction #-}
>
> foo :: _ => _outer
> foo x = round $ (undefined::_inner) (1 + x)
> }}}
> This produces the following output in GHCi:
> {{{
> Foo.hs:5:8: Warning:
>     Found hole ‘_’ with inferred constraints: (Integral b, Num a)
>     In the type signature for ‘foo’: _ => _outer
>
> Foo.hs:5:13: Warning:
>     Found hole ‘_outer’ with type: a -> b
>     Where: ‘b’ is a rigid type variable bound by
>                the inferred type of foo :: (Integral b, Num a) => a -> b
>                at Foo.hs:6:1
>            ‘a’ is a rigid type variable bound by
>                the inferred type of foo :: (Integral b, Num a) => a -> b
>                at Foo.hs:6:1
>     In the type signature for ‘foo’: _ => _outer
>
> Foo.hs:6:29: Warning:
>     Found hole ‘_inner’ with type: a -> Double
>     Where: ‘a’ is a rigid type variable bound by
>                the inferred type of foo :: (Integral b, Num a) => a -> b
>                at Foo.hs:6:1
>     Relevant bindings include
>       x :: a (bound at Foo.hs:6:5)
>       foo :: a -> b (bound at Foo.hs:6:1)
>     In an expression type signature: _inner
>     In the expression: undefined :: _inner
>     In the second argument of ‘($)’, namely
>       ‘(undefined :: _inner) (1 + x)’
> Ok, modules loaded: Main.
> }}}
> The inferred constraints for `_` (which I can't give a name,
> unfortunately) and the type reported in place of `_outer` are exactly
> what I expected. The type for `_inner` surprises me. Okay, the type is
> ambiguous, so for anything as general as `undefined`, arguably, it would
> need to default to something.
>
> Let's use a typed hole instead of `undefined`:
> {{{#!hs
> foo :: _ => _outer
> foo x = round $ _hole (1 + x)
> }}}
> gives
> {{{
> Foo.hs:6:17:
>     Found hole ‘_hole’ with type: a -> Double
>     Where: ‘a’ is a rigid type variable bound by
>                the inferred type of foo :: a -> b at Foo.hs:6:1
>     Relevant bindings include
>       x :: a (bound at Foo.hs:6:5)
>       foo :: a -> b (bound at Foo.hs:6:1)
>     In the expression: _hole
>     In the second argument of ‘($)’, namely ‘_hole (1 + x)’
>     In the expression: round $ _hole (1 + x)
> Failed, modules loaded: none.
> }}}
> Holy Guacamole, it still defaults to `Double`. I would consider this a
> bug, because GHC is telling me, that whatever I put there must result in
> a `Double`, which is too restrictive to be true. However, I seem to
> recall from the OutsideIn paper that there were some cases, even without
> GADTs, where principality was difficult. Was this one of them?
>
> Moving on, I was actually trying to get all my holes typed for me in one
> compiler execution. GHC behaves according to spec; typed holes produce
> errors by default and when something breaks on an error, it doesn't
> produce the warnings for partial type signatures. Let's `-fdefer-typed-
> holes` and compile again:
> {{{
> Prelude> :set -fdefer-typed-holes
> Prelude> :r
> [1 of 1] Compiling Main             ( Foo.hs, interpreted )
>
> Foo.hs:5:8: Warning:
>     Found hole ‘_’ with inferred constraints: ()
>     In the type signature for ‘foo’: _ => _outer
>
> Foo.hs:5:13: Warning:
>     Found hole ‘_outer’ with type: a -> b
>     Where: ‘b’ is a rigid type variable bound by
>                the inferred type of foo :: a -> b at Foo.hs:6:1
>            ‘a’ is a rigid type variable bound by
>                the inferred type of foo :: a -> b at Foo.hs:6:1
>     In the type signature for ‘foo’: _ => _outer
>
> Foo.hs:6:17: Warning:
>     Found hole ‘_hole’ with type: a -> Double
>     Where: ‘a’ is a rigid type variable bound by
>                the inferred type of foo :: a -> b at Foo.hs:6:1
>     Relevant bindings include
>       x :: a (bound at Foo.hs:6:5)
>       foo :: a -> b (bound at Foo.hs:6:1)
>     In the expression: _hole
>     In the second argument of ‘($)’, namely ‘_hole (1 + x)’
>     In the expression: round $ _hole (1 + x)
> Ok, modules loaded: Main.
> }}}
> Surely, this must be wrong. Suddenly `()` is the inferred set of
> constraints and an unconstrained `a -> b` will do for `_outer`. I would
> argue that the `1 +` still demainds `Num a`, even if `round`'s `RealFrac`
> constraint is satisfied by `_hole` producing a `Double`.
>
> As said, maybe the erroneous types reported when `-fdefer-typed-holes`
> are a separate issue from the type of `_hole` not being the principal
> type, but I'm unsure, so I reported them together.

New description:

 Maybe this should be one bug report and one feature request, but for now,
 I'll report them together. Consider the following program:
 {{{#!hs
 {-#LANGUAGE PartialTypeSignatures #-}
 {-#LANGUAGE NamedWildCards #-}
 {-#LANGUAGE NoMonomorphismRestriction #-}

 foo :: _ => _outer
 foo x = round $ (undefined::_inner) (1 + x)
 }}}
 This produces the following output in GHCi:
 {{{
 Foo.hs:5:8: Warning:
     Found hole ‘_’ with inferred constraints: (Integral b, Num a)
     In the type signature for ‘foo’: _ => _outer

 Foo.hs:5:13: Warning:
     Found hole ‘_outer’ with type: a -> b
     Where: ‘b’ is a rigid type variable bound by
                the inferred type of foo :: (Integral b, Num a) => a -> b
                at Foo.hs:6:1
            ‘a’ is a rigid type variable bound by
                the inferred type of foo :: (Integral b, Num a) => a -> b
                at Foo.hs:6:1
     In the type signature for ‘foo’: _ => _outer

 Foo.hs:6:29: Warning:
     Found hole ‘_inner’ with type: a -> Double
     Where: ‘a’ is a rigid type variable bound by
                the inferred type of foo :: (Integral b, Num a) => a -> b
                at Foo.hs:6:1
     Relevant bindings include
       x :: a (bound at Foo.hs:6:5)
       foo :: a -> b (bound at Foo.hs:6:1)
     In an expression type signature: _inner
     In the expression: undefined :: _inner
     In the second argument of ‘($)’, namely
       ‘(undefined :: _inner) (1 + x)’
 Ok, modules loaded: Main.
 }}}
 The inferred constraints for `_` (which I can't give a name,
 unfortunately) and the type reported in place of `_outer` are exactly what
 I expected. The type for `_inner` surprises me. Okay, the type is
 ambiguous, so for anything as general as `undefined`, arguably, it would
 need to default to something.

 Let's use a typed hole instead of `undefined`:
 {{{#!hs
 foo :: _ => _outer
 foo x = round $ _hole (1 + x)
 }}}
 gives
 {{{
 Foo.hs:6:17:
     Found hole ‘_hole’ with type: a -> Double
     Where: ‘a’ is a rigid type variable bound by
                the inferred type of foo :: a -> b at Foo.hs:6:1
     Relevant bindings include
       x :: a (bound at Foo.hs:6:5)
       foo :: a -> b (bound at Foo.hs:6:1)
     In the expression: _hole
     In the second argument of ‘($)’, namely ‘_hole (1 + x)’
     In the expression: round $ _hole (1 + x)
 Failed, modules loaded: none.
 }}}
 Holy Guacamole, it still defaults to `Double`. I would consider this a
 bug, because GHC is telling me, that whatever I put there must result in a
 `Double`, which is too restrictive to be true. However, I seem to recall
 from the OutsideIn paper that there were some cases, even without GADTs,
 where principality was difficult. Was this one of them?

 Moving on, I was actually trying to get all my holes typed for me in one
 compiler execution. GHC behaves according to spec; typed holes produce
 errors by default and when something breaks on an error, it doesn't
 produce the warnings for partial type signatures. Let's `-fdefer-typed-
 holes` and compile again:
 {{{
 Prelude> :set -fdefer-typed-holes
 Prelude> :r
 [1 of 1] Compiling Main             ( Foo.hs, interpreted )

 Foo.hs:5:8: Warning:
     Found hole ‘_’ with inferred constraints: ()
     In the type signature for ‘foo’: _ => _outer

 Foo.hs:5:13: Warning:
     Found hole ‘_outer’ with type: a -> b
     Where: ‘b’ is a rigid type variable bound by
                the inferred type of foo :: a -> b at Foo.hs:6:1
            ‘a’ is a rigid type variable bound by
                the inferred type of foo :: a -> b at Foo.hs:6:1
     In the type signature for ‘foo’: _ => _outer

 Foo.hs:6:17: Warning:
     Found hole ‘_hole’ with type: a -> Double
     Where: ‘a’ is a rigid type variable bound by
                the inferred type of foo :: a -> b at Foo.hs:6:1
     Relevant bindings include
       x :: a (bound at Foo.hs:6:5)
       foo :: a -> b (bound at Foo.hs:6:1)
     In the expression: _hole
     In the second argument of ‘($)’, namely ‘_hole (1 + x)’
     In the expression: round $ _hole (1 + x)
 Ok, modules loaded: Main.
 }}}
 Surely, this must be wrong. Suddenly `()` is the inferred set of
 constraints and an unconstrained `a -> b` will do for `_outer`. I would
 argue that the `1 +` still demainds `Num a` and that `round` still
 requires an instance of `Integral b`, even if `round`'s `RealFrac`
 constraint is satisfied by `_hole` producing a `Double`.

 As said, maybe the erroneous types reported when `-fdefer-typed-holes` are
 a separate issue from the type of `_hole` not being the principal type,
 but I'm unsure, so I reported them together.

--

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/10875#comment:1>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list