From 7b9437229b4b4af3fd6b0e4a286cf9a398481d07 Mon Sep 17 00:00:00 2001 From: Phil Hazelden <phazelden@triviumre.com> Date: Tue, 1 Nov 2022 12:17:59 +0000 Subject: [PATCH] Improve promoted type applications in GHC < 9. This is https://github.com/lspitzner/brittany/pull/376 backported so we can use it on GHC 8.10.7. Backporting the tests would have been a hassle so I didn't bother. --- .../Brittany/Internal/Layouters/Type.hs | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/Language/Haskell/Brittany/Internal/Layouters/Type.hs b/src/Language/Haskell/Brittany/Internal/Layouters/Type.hs index 3437fcd..e8bad7c 100644 --- a/src/Language/Haskell/Brittany/Internal/Layouters/Type.hs +++ b/src/Language/Haskell/Brittany/Internal/Layouters/Type.hs @@ -50,8 +50,7 @@ layoutType ltype@(L _ typ) = docWrapNode ltype $ case typ of #else /* ghc-8.6 */ Promoted -> docSeq #endif - [ docSeparator - , docTick + [ docTick , docWrapNode name $ docLit t ] NotPromoted -> docWrapNode name $ docLit t @@ -562,14 +561,25 @@ layoutType ltype@(L _ typ) = docWrapNode ltype $ case typ of HsRecTy{} -> -- TODO briDocByExactInlineOnly "HsRecTy{}" ltype HsExplicitListTy _ _ typs -> do + -- `'['Foo]` isn't valid because it parses as a character. So if the list + -- starts with a promoted type var, we swap to `'[ 'Foo ]`. + let + sepIfHeadPromoted = case typs of + (L _ t) : _ | startsWithTick t -> docSeparator + _ -> docEmpty + + -- When rendering on multiple lines, this causes commas to line up with the + -- opening bracket. Unfortunately it also adds unnecessary space when + -- rendering on a single line. + let specialCommaSep = appSep $ docLit $ Text.pack " ," + typDocs <- docSharedWrapper layoutType `mapM` typs hasComments <- hasAnyCommentsBelow ltype - let specialCommaSep = appSep $ docLit $ Text.pack " ," docAlt [ docSeq - $ [docLit $ Text.pack "'["] + $ [docLit $ Text.pack "'[", sepIfHeadPromoted] ++ List.intersperse specialCommaSep (docForceSingleline <$> typDocs) - ++ [docLit $ Text.pack "]"] + ++ [sepIfHeadPromoted, docLit $ Text.pack "]"] , case splitFirstLast typDocs of FirstLastEmpty -> docSeq [ docLit $ Text.pack "'[" @@ -578,7 +588,9 @@ layoutType ltype@(L _ typ) = docWrapNode ltype $ case typ of FirstLastSingleton e -> docAlt [ docSeq [ docLit $ Text.pack "'[" + , sepIfHeadPromoted , docNodeAnnKW ltype (Just AnnOpenS) $ docForceSingleline e + , sepIfHeadPromoted , docLit $ Text.pack "]" ] , docSetBaseY $ docLines @@ -593,7 +605,7 @@ layoutType ltype@(L _ typ) = docWrapNode ltype $ case typ of FirstLast e1 ems eN -> runFilteredAlternative $ do addAlternativeCond (not hasComments) $ docSeq - $ [docLit $ Text.pack "'["] + $ [docLit $ Text.pack "'[", sepIfHeadPromoted] ++ List.intersperse specialCommaSep (docForceSingleline <$> (e1:ems ++ [docNodeAnnKW ltype (Just AnnOpenS) eN])) ++ [docLit $ Text.pack " ]"] addAlternative $ @@ -663,3 +675,10 @@ processTyVarBndrsSingleline bndrDocs = bndrDocs >>= \case , docForceSingleline $ doc , docLit $ Text.pack ")" ] + +-- | Determine if the type starts with a tick mark (single quote) when rendered. +startsWithTick :: HsType pass -> Bool +startsWithTick = \case + HsTyVar _ IsPromoted _ -> True + HsAppTy _ (L _ t) _ -> startsWithTick t + _ -> False