[GHC] #12936: Type inference regression in GHC HEAD

GHC ghc-devs at haskell.org
Wed Dec 7 02:03:33 UTC 2016


#12936: Type inference regression in GHC HEAD
-------------------------------------+-------------------------------------
           Reporter:  RyanGlScott    |             Owner:
               Type:  bug            |            Status:  new
           Priority:  high           |         Milestone:  8.2.1
          Component:  Compiler       |           Version:  8.1
  (Type checker)                     |
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  GHC rejects
  Unknown/Multiple                   |  valid program
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 First noticed in https://ghc.haskell.org/trac/ghc/ticket/12790#comment:8.
 This causes `parsec-3.1.11` to fail to build with GHC HEAD.

 Here is as small of a test case that I can manage, with no dependencies:

 {{{#!hs
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 module Parsec (makeTokenParser) where

 import Data.Char (digitToInt)

 data ParsecT s u (m :: * -> *) a

 instance Functor (ParsecT s u m) where
     fmap = undefined

 instance Applicative (ParsecT s u m) where
     pure = undefined
     (<*>) = undefined

 instance Monad (ParsecT s u m) where
     return = undefined
     (>>=)  = undefined
     fail   = undefined

 parserZero :: ParsecT s u m a
 parserZero = undefined

 infixr 1 <|>
 (<|>) :: (ParsecT s u m a) -> (ParsecT s u m a) -> (ParsecT s u m a)
 (<|>) = undefined

 class (Monad m) => Stream s m t | s -> t where

 digit :: (Stream s m Char) => ParsecT s u m Char
 digit = undefined

 hexDigit :: (Stream s m Char) => ParsecT s u m Char
 hexDigit = undefined

 octDigit :: (Stream s m Char) => ParsecT s u m Char
 octDigit = undefined

 option :: (Stream s m t) => a -> ParsecT s u m a -> ParsecT s u m a
 option = undefined

 many1 :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m [a]
 many1 = undefined

 data GenTokenParser s u m
     = TokenParser {
         float            :: ParsecT s u m Double,
         naturalOrFloat   :: ParsecT s u m (Either Integer Double)
     }

 makeTokenParser :: (Stream s m Char) => GenTokenParser s u m
 makeTokenParser
     = TokenParser{
                    float = float_
                  , naturalOrFloat = naturalOrFloat_
                  }
     where

     -----------------------------------------------------------
     -- Numbers
     -----------------------------------------------------------
     naturalOrFloat_ = lexeme natFloat

     float_          = lexeme floating

     -- floats
     floating        = do{ n <- decimal
                         ; fractExponent n
                         }


     natFloat        =     zeroNumFloat
                       <|> decimalFloat

     zeroNumFloat    =  do{ n <- hexadecimal <|> octal
                          ; return (Left n)
                          }
                     <|> decimalFloat

     decimalFloat    = do{ n <- decimal
                         ; option (Left n)
                                  (fractFloat n)
                         }

     fractFloat n    = do{ f <- fractExponent n
                         ; return (Right f)
                         }

     fractExponent n = do{ fract <- fraction
                         ; expo  <- option "" exponent'
                         ; readDouble (show n ++ fract ++ expo)
                         }
                     <|>
                       do{ expo <- exponent'
                         ; readDouble (show n ++ expo)
                         }
                       where
                         readDouble s =
                           case reads s of
                             [(x, "")] -> return x
                             _         -> parserZero

     fraction        = do{ digits <- many1 digit
                         ; return ('.' : digits)
                         }

     exponent'       = do{ e <- decimal
                         ; return (show e)
                         }

     -- integers and naturals
     decimal         = number 10 digit
     hexadecimal     = number 16 hexDigit
     octal           = number 8 octDigit

     number base baseDigit
         = do{ digits <- many1 baseDigit
             ; let n = foldl (\x d -> base*x + toInteger (digitToInt d)) 0
 digits
             ; seq n (return n)
             }

     -----------------------------------------------------------
     -- White space & symbols
     -----------------------------------------------------------
     lexeme p = do{ x <- p; whiteSpace; return x  }
     whiteSpace = return ()
 }}}

 In GHC 8.0.1 and 8.0.2, this compiles without issue. But on GHC HEAD:

 {{{
 $ ~/Software/ghc/inplace/bin/ghc-stage2 Parsec.hs
 [1 of 1] Compiling Parsec           ( Parsec.hs, Parsec.o )

 Parsec.hs:83:27: error:
     • Could not deduce (Stream s m t0) arising from a use of ‘option’
       from the context: Stream s m Char
         bound by the type signature for:
                    makeTokenParser :: Stream s m Char => GenTokenParser s
 u m
         at Parsec.hs:53:1-60
       The type variable ‘t0’ is ambiguous
       Relevant bindings include
         decimalFloat :: ParsecT s u1 m (Either Integer Double)
           (bound at Parsec.hs:82:5)
         fractFloat :: forall b a1 u a2.
                       (Read b, Show a2) =>
                       a2 -> ParsecT s u m (Either a1 b)
           (bound at Parsec.hs:87:5)
         fractExponent :: forall a1 u a2.
                          (Show a2, Read a1) =>
                          a2 -> ParsecT s u m a1
           (bound at Parsec.hs:91:5)
         fraction :: forall u. ParsecT s u m [Char]
           (bound at Parsec.hs:105:5)
         exponent' :: forall u. ParsecT s u m String
           (bound at Parsec.hs:109:5)
         decimal :: forall u. ParsecT s u m Integer
           (bound at Parsec.hs:114:5)
         lexeme :: forall b. ParsecT s u m b -> ParsecT s u m b
           (bound at Parsec.hs:127:5)
         (Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-
 relevant-binds)
     • In a stmt of a 'do' block: option (Left n) (fractFloat n)
       In the expression:
         do { n <- decimal;
              option (Left n) (fractFloat n) }
       In an equation for ‘decimalFloat’:
           decimalFloat
             = do { n <- decimal;
                    option (Left n) (fractFloat n) }
 }}}

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


More information about the ghc-tickets mailing list