lspitzner / brittany

haskell source code formatter
GNU Affero General Public License v3.0
687 stars 72 forks source link

Formatting removes key program components in custom data structures #368

Open L0neGamer opened 2 years ago

L0neGamer commented 2 years ago

See below of the before and after of running brittany --config-file=brittany.yaml --write-mode=inplace $(git ls-files '*.hs') using the default config on versions 0.14.0.0, and 0.14.0.2.

before after

As is evident, the code produced is completely unable to compile.

tfausak commented 2 years ago

Dang, that's a gnarly bug! Unfortunately Brittany only barely supports GADTs. See #217, #242, and #261 for some other examples.

L0neGamer commented 2 years ago

I managed to resist putting "catastrophic reformatting on data structures" as the title, cause yeah this is bad lol.

Is there anywhere in particular in the code where this could be solved? I'm not familiar with formatters.

prikhi commented 2 years ago

This is currently preventing us from using brittany after we upgrade to LTS-19, so I did a little digging...

GADTs trigger this formatting line in Internal.Layouters.DataDecl.layoutDataDecl:

  _ -> briDocByExactNoComment ltycl

so I thought maybe this was an issue in ghc-exactprint, made a little harness that uses exactprint to parse & print a GADT but I get the proper output back:

doIt :: FilePath -> IO ()
doIt fp = do
    raw <- readFile fp
    putStr raw
    putStrLn $ replicate 80 '-'
    (anns, res) <- either (error . show . bagToList) return =<< parseModule fp
    putStrLn $ exactPrint res anns
λ: :l ExactPrintHarness.hs 
[1 of 1] Compiling ExactPrintHarness ( ExactPrintHarness.hs, interpreted )
Ok, one module loaded.
λ: doIt "GadtFormatting.hs"
{-# LANGUAGE GADTs #-}
module GadtFormatting where

data MyGadt a where
    MyInt :: Int -> MyGadt Int
--------------------------------------------------------------------------------
{-# LANGUAGE GADTs #-}
module GadtFormatting where

data MyGadt a where
    MyInt :: Int -> MyGadt Int

logging out the ltycl in that case branch(with briDocByExactNoComment $ traceShow (showSDocUnsafe $ ppr ltycl) $ ltycl via new test file I wrote) gives us:

data Stuff a\n  where\n    AnInt :: Int -> Stuff Int\n    AString :: String -> Stuff String

So I'm inclined to believe the problem lies somewhere within briDocByExactNoComment, but I haven't dug much further than that yet.