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