haskell-suite / haskell-src-exts

Manipulating Haskell source: abstract syntax, lexer, parser, and pretty-printer
Other
194 stars 95 forks source link

New-style qualified type operators not supported. #79

Open lichtemo opened 10 years ago

lichtemo commented 10 years ago

pp-haskell pretty prints for example Prelude.* to Prelude[space].* which is not correct anymore

UnkindPartition commented 10 years ago

Can you provide a reproducible test case? Here's what I observe:

Prelude Language.Haskell.Exts> let ParseOk ast = parseExp "1 Prelude.* 2"
Prelude Language.Haskell.Exts> ast
InfixApp (Lit (Int 1)) (QVarOp (Qual (ModuleName "Prelude") (Symbol "*"))) (Lit (Int 2))
Prelude Language.Haskell.Exts> prettyPrint ast
"1 Prelude.* 2"
lichtemo commented 10 years ago

When I use TypeOperators s :: Int P.-> Bool is pretty printed to s :: Int P .-> Bool

But the problem only occurs with the -> operator. I am actually nut sure, whether -> is a valid type operator but the example is from at least two Haskell files from hackage.

UnkindPartition commented 10 years ago

Oh, so this is about type operators.

This happens because it parses the dot as a part of the .-> operator.

Prelude Language.Haskell.Exts> parseTypeWithMode defaultParseMode { extensions = [EnableExtension  TypeOperators] } "Int P.-> Bool"
ParseOk (TyInfix (TyApp (TyCon (UnQual (Ident "Int"))) (TyCon (UnQual (Ident "P")))) (UnQual (Symbol ".->")) (TyCon (UnQual (Ident "Bool"))))

That in turn happens because -> is syntax, not an operator.

HSE does correctly parse old-style qualified type ops (ones that begin with a colon):

Prelude Language.Haskell.Exts> parseTypeWithMode defaultParseMode { extensions = [EnableExtension  TypeOperators ] } "Int P.:> Bool"
ParseOk (TyInfix (TyCon (UnQual (Ident "Int"))) (Qual (ModuleName "P") (Symbol ":>")) (TyCon (UnQual (Ident "Bool"))))

It doesn't know about new-style type operator constructors (that can contain any symbols):

Prelude Language.Haskell.Exts> parseTypeWithMode defaultParseMode { extensions = [EnableExtension  TypeOperators ] } "Int P.> Bool"
ParseFailed (SrcLoc {srcFilename = "<unknown>.hs", srcLine = 1, srcColumn = 5}) "Parse error: P.>"
danbst commented 10 years ago

There is one more not supported TypeOperators feature - type operator export. Combined into one test file:

{-# LANGUAGE TypeOperators #-}
module TypeOperatorDataConstructor 
   ((+)(..), type (+))                                           -- not supported
where

data a + b = L a | R b
either1 :: (t1 -> t) -> (t2 -> t) -> (t1 + t2) -> t    -- pass
either2 :: (t1 -> t) -> (t2 -> t) -> (t1 E.+ t2) -> t  -- not supported
ndmitchell commented 6 years ago

There's a reasonably complete test case from @bpfoley at https://github.com/ndmitchell/hlint/issues/400:

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeOperators #-}                                                  

module N where

type (++) a b = (a,b)

-- Correctly parses OK in GHCi & hlint
f1 :: Eq (Bool ++ Bool) => a
f1 = undefined

-- Correctly parses OK in GHCi & hlint
f2 :: Eq ((N.++) Bool Bool) => a
f2 = undefined

-- Parses OK in GHCi, but incorrectly a parse error in hlint
f3 :: Eq (Bool N.++ Bool) => a
f3 = undefined

-- Parse error in GHCi (because it's a prefix op), but incorrectly
-- parses OK in hlint
f4 :: Eq (Bool (N.++) Bool) => a
f4 = undefined