[Git][ghc/ghc][master] 2 commits: template-haskell: move some identifiers from ghc-internal to template-haskell

Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC Commits: 5b841d82 by Teo Camarasu at 2025-08-14T17:57:56-04:00 template-haskell: move some identifiers from ghc-internal to template-haskell These identifiers are not used internally by the compiler. Therefore we have no reason for them to be in ghc-internal. By moving them to template-haskell, we benefit from it being easier to change them and we avoid having to build them in stage0. Resolves #26048 - - - - - 33e2c7e5 by Teo Camarasu at 2025-08-14T17:57:56-04:00 template-haskell: transfer $infix note to public module This Haddock note should be in the public facing module - - - - - 10 changed files: - libraries/ghc-internal/src/GHC/Internal/TH/Lib.hs - libraries/ghc-internal/src/GHC/Internal/TH/Lift.hs - libraries/ghc-internal/src/GHC/Internal/TH/Syntax.hs - libraries/template-haskell/Language/Haskell/TH/Lib.hs - libraries/template-haskell/Language/Haskell/TH/Quote.hs - libraries/template-haskell/Language/Haskell/TH/Syntax.hs - libraries/template-haskell/tests/all.T - testsuite/tests/interface-stability/template-haskell-exports.stdout - testsuite/tests/quasiquotation/T4491/test.T - testsuite/tests/th/Makefile Changes: ===================================== libraries/ghc-internal/src/GHC/Internal/TH/Lib.hs ===================================== @@ -555,20 +555,6 @@ pragInlD name inline rm phases pragOpaqueD :: Quote m => Name -> m Dec pragOpaqueD name = pure $ PragmaD $ OpaqueP name -{-# DEPRECATED pragSpecD "Please use 'pragSpecED' instead. 'pragSpecD' will be removed in GHC 9.18." #-} -pragSpecD :: Quote m => Name -> m Type -> Phases -> m Dec -pragSpecD n ty phases - = do - ty1 <- ty - pure $ PragmaD $ SpecialiseP n ty1 Nothing phases - -{-# DEPRECATED pragSpecInlD "Please use 'pragSpecInlED' instead. 'pragSpecInlD' will be removed in GHC 9.18." #-} -pragSpecInlD :: Quote m => Name -> m Type -> Inline -> Phases -> m Dec -pragSpecInlD n ty inline phases - = do - ty1 <- ty - pure $ PragmaD $ SpecialiseP n ty1 (Just inline) phases - pragSpecED :: Quote m => Maybe [m (TyVarBndr ())] -> [m RuleBndr] -> m Exp @@ -868,22 +854,6 @@ implicitParamT n t t' <- t pure $ ImplicitParamT n t' -{-# DEPRECATED classP "As of template-haskell-2.10, constraint predicates (Pred) are just types (Type), in keeping with ConstraintKinds. Please use 'conT' and 'appT'." #-} -classP :: Quote m => Name -> [m Type] -> m Pred -classP cla tys - = do - tysl <- sequenceA tys - pure (foldl AppT (ConT cla) tysl) - -{-# DEPRECATED equalP "As of template-haskell-2.10, constraint predicates (Pred) are just types (Type), in keeping with ConstraintKinds. Please see 'equalityT'." #-} -equalP :: Quote m => m Type -> m Type -> m Pred -equalP tleft tright - = do - tleft1 <- tleft - tright1 <- tright - eqT <- equalityT - pure (foldl AppT eqT [tleft1, tright1]) - promotedT :: Quote m => Name -> m Type promotedT = pure . PromotedT @@ -906,20 +876,6 @@ noSourceStrictness = pure NoSourceStrictness sourceLazy = pure SourceLazy sourceStrict = pure SourceStrict -{-# DEPRECATED isStrict - ["Use 'bang'. See https://gitlab.haskell.org/ghc/ghc/wikis/migration/8.0. ", - "Example usage: 'bang noSourceUnpackedness sourceStrict'"] #-} -{-# DEPRECATED notStrict - ["Use 'bang'. See https://gitlab.haskell.org/ghc/ghc/wikis/migration/8.0. ", - "Example usage: 'bang noSourceUnpackedness noSourceStrictness'"] #-} -{-# DEPRECATED unpacked - ["Use 'bang'. See https://gitlab.haskell.org/ghc/ghc/wikis/migration/8.0. ", - "Example usage: 'bang sourceUnpack sourceStrict'"] #-} -isStrict, notStrict, unpacked :: Quote m => m Strict -isStrict = bang noSourceUnpackedness sourceStrict -notStrict = bang noSourceUnpackedness noSourceStrictness -unpacked = bang sourceUnpack sourceStrict - bang :: Quote m => m SourceUnpackedness -> m SourceStrictness -> m Bang bang u s = do u' <- u s' <- s @@ -931,16 +887,6 @@ bangType = liftA2 (,) varBangType :: Quote m => Name -> m BangType -> m VarBangType varBangType v bt = (\(b, t) -> (v, b, t)) <$> bt -{-# DEPRECATED strictType - "As of @template-haskell-2.11.0.0@, 'StrictType' has been replaced by 'BangType'. Please use 'bangType' instead." #-} -strictType :: Quote m => m Strict -> m Type -> m StrictType -strictType = bangType - -{-# DEPRECATED varStrictType - "As of @template-haskell-2.11.0.0@, 'VarStrictType' has been replaced by 'VarBangType'. Please use 'varBangType' instead." #-} -varStrictType :: Quote m => Name -> m StrictType -> m VarStrictType -varStrictType = varBangType - -- * Type Literals -- MonadFail here complicates things (a lot) because it would mean we would ===================================== libraries/ghc-internal/src/GHC/Internal/TH/Lift.hs ===================================== @@ -24,40 +24,22 @@ module GHC.Internal.TH.Lift ( Lift(..) - -- * Generic Lift implementations - , dataToQa - , dataToCodeQ - , dataToExpQ - , liftDataTyped - , liftData - , dataToPatQ -- * Wired-in names , liftString - , trueName - , falseName - , nothingName - , justName - , leftName - , rightName - , nonemptyName ) where import GHC.Internal.TH.Syntax import qualified GHC.Internal.TH.Lib as Lib (litE) -- See wrinkle (W4) of Note [Tracking dependencies on primitives] -import GHC.Internal.Lexeme ( startsVarSym, startsVarId ) import GHC.Internal.Data.Either -import GHC.Internal.Type.Reflection import GHC.Internal.Data.Bool import GHC.Internal.Base hiding (NonEmpty(..), Type, Module, inline) -import GHC.Internal.Data.Foldable import GHC.Internal.Data.NonEmpty (NonEmpty(..)) import GHC.Internal.Integer import GHC.Internal.Real import GHC.Internal.Word import GHC.Internal.Int -import GHC.Internal.Data.Data hiding (Fixity) import GHC.Internal.Natural import GHC.Internal.ForeignPtr @@ -294,20 +276,6 @@ deriving instance (Lift a, Lift b, Lift c, Lift d, Lift e, Lift f) deriving instance (Lift a, Lift b, Lift c, Lift d, Lift e, Lift f, Lift g) => Lift (# a | b | c | d | e | f | g #) -trueName, falseName :: Name -trueName = 'True -falseName = 'False - -nothingName, justName :: Name -nothingName = 'Nothing -justName = 'Just - -leftName, rightName :: Name -leftName = 'Left -rightName = 'Right - -nonemptyName :: Name -nonemptyName = '(:|) ----------------------------------------------------- -- @@ -443,157 +411,3 @@ deriving instance Lift Info deriving instance Lift AnnLookup -- | @since template-haskell-2.22.1.0 deriving instance Lift Extension - ------------------------------------------------------ --- --- Generic Lift implementations --- ------------------------------------------------------ - --- | 'dataToQa' is an internal utility function for constructing generic --- conversion functions from types with 'Data' instances to various --- quasi-quoting representations. See the source of 'dataToExpQ' and --- 'dataToPatQ' for two example usages: @mkCon@, @mkLit@ --- and @appQ@ are overloadable to account for different syntax for --- expressions and patterns; @antiQ@ allows you to override type-specific --- cases, a common usage is just @const Nothing@, which results in --- no overloading. -dataToQa :: forall m a k q. (Quote m, Data a) - => (Name -> k) - -> (Lit -> m q) - -> (k -> [m q] -> m q) - -> (forall b . Data b => b -> Maybe (m q)) - -> a - -> m q -dataToQa mkCon mkLit appCon antiQ t = - case antiQ t of - Nothing -> - case constrRep constr of - AlgConstr _ -> - appCon (mkCon funOrConName) conArgs - where - funOrConName :: Name - funOrConName = - case showConstr constr of - "(:)" -> Name (mkOccName ":") - (NameG DataName - (mkPkgName "ghc-internal") - (mkModName "GHC.Internal.Types")) - con@"[]" -> Name (mkOccName con) - (NameG DataName - (mkPkgName "ghc-internal") - (mkModName "GHC.Internal.Types")) - con@('(':_) -> Name (mkOccName con) - (NameG DataName - (mkPkgName "ghc-internal") - (mkModName "GHC.Internal.Tuple")) - - -- Tricky case: see Note [Data for non-algebraic types] - fun@(x:_) | startsVarSym x || startsVarId x - -> mkNameG_v tyconPkg tyconMod fun - con -> mkNameG_d tyconPkg tyconMod con - - where - tycon :: TyCon - tycon = (typeRepTyCon . typeOf) t - - tyconPkg, tyconMod :: String - tyconPkg = tyConPackage tycon - tyconMod = tyConModule tycon - - conArgs :: [m q] - conArgs = gmapQ (dataToQa mkCon mkLit appCon antiQ) t - IntConstr n -> - mkLit $ IntegerL n - FloatConstr n -> - mkLit $ RationalL n - CharConstr c -> - mkLit $ CharL c - where - constr :: Constr - constr = toConstr t - - Just y -> y - - -{- Note [Data for non-algebraic types] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Class Data was originally intended for algebraic data types. But -it is possible to use it for abstract types too. For example, in -package `text` we find - - instance Data Text where - ... - toConstr _ = packConstr - - packConstr :: Constr - packConstr = mkConstr textDataType "pack" [] Prefix - -Here `packConstr` isn't a real data constructor, it's an ordinary -function. Two complications - -* In such a case, we must take care to build the Name using - mkNameG_v (for values), not mkNameG_d (for data constructors). - See #10796. - -* The pseudo-constructor is named only by its string, here "pack". - But 'dataToQa' needs the TyCon of its defining module, and has - to assume it's defined in the same module as the TyCon itself. - But nothing enforces that; #12596 shows what goes wrong if - "pack" is defined in a different module than the data type "Text". - -} - --- | A typed variant of 'dataToExpQ'. -dataToCodeQ :: (Quote m, Data a) - => (forall b . Data b => b -> Maybe (Code m b)) - -> a -> Code m a -dataToCodeQ f = unsafeCodeCoerce . dataToExpQ (fmap unTypeCode . f) - --- | 'dataToExpQ' converts a value to a 'Exp' representation of the --- same value, in the SYB style. It is generalized to take a function --- override type-specific cases; see 'liftData' for a more commonly --- used variant. -dataToExpQ :: (Quote m, Data a) - => (forall b . Data b => b -> Maybe (m Exp)) - -> a - -> m Exp -dataToExpQ = dataToQa varOrConE litE (foldl appE) - where - -- Make sure that VarE is used if the Constr value relies on a - -- function underneath the surface (instead of a constructor). - -- See #10796. - varOrConE s = - case nameSpace s of - Just VarName -> return (VarE s) - Just (FldName {}) -> return (VarE s) - Just DataName -> return (ConE s) - _ -> error $ "Can't construct an expression from name " - ++ showName s - appE x y = do { a <- x; b <- y; return (AppE a b)} - litE c = return (LitE c) - --- | A typed variant of 'liftData'. -liftDataTyped :: (Quote m, Data a) => a -> Code m a -liftDataTyped = dataToCodeQ (const Nothing) - --- | 'liftData' is a variant of 'lift' in the 'Lift' type class which --- works for any type with a 'Data' instance. -liftData :: (Quote m, Data a) => a -> m Exp -liftData = dataToExpQ (const Nothing) - --- | 'dataToPatQ' converts a value to a 'Pat' representation of the same --- value, in the SYB style. It takes a function to handle type-specific cases, --- alternatively, pass @const Nothing@ to get default behavior. -dataToPatQ :: (Quote m, Data a) - => (forall b . Data b => b -> Maybe (m Pat)) - -> a - -> m Pat -dataToPatQ = dataToQa id litP conP - where litP l = return (LitP l) - conP n ps = - case nameSpace n of - Just DataName -> do - ps' <- sequence ps - return (ConP n [] ps') - _ -> error $ "Can't construct a pattern from name " - ++ showName n ===================================== libraries/ghc-internal/src/GHC/Internal/TH/Syntax.hs ===================================== @@ -22,9 +22,6 @@ module GHC.Internal.TH.Syntax -- * Language extensions , module GHC.Internal.LanguageExtensions , ForeignSrcLang(..) - -- * Notes - -- ** Unresolved Infix - -- $infix ) where #ifdef BOOTSTRAP_TH @@ -847,12 +844,6 @@ addTempFile suffix = Q (qAddTempFile suffix) addTopDecls :: [Dec] -> Q () addTopDecls ds = Q (qAddTopDecls ds) --- | -addForeignFile :: ForeignSrcLang -> String -> Q () -addForeignFile = addForeignSource -{-# DEPRECATED addForeignFile - "Use 'Language.Haskell.TH.Syntax.addForeignSource' instead" - #-} -- deprecated in 8.6 -- | Emit a foreign file which will be compiled and linked to the object for -- the current module. Currently only languages that can be compiled with @@ -1614,73 +1605,6 @@ maxPrecedence = (9::Int) defaultFixity :: Fixity defaultFixity = Fixity maxPrecedence InfixL - -{- -Note [Unresolved infix] -~~~~~~~~~~~~~~~~~~~~~~~ --} -{- $infix #infix# - -When implementing antiquotation for quasiquoters, one often wants -to parse strings into expressions: - -> parse :: String -> Maybe Exp - -But how should we parse @a + b * c@? If we don't know the fixities of -@+@ and @*@, we don't know whether to parse it as @a + (b * c)@ or @(a -+ b) * c@. - -In cases like this, use 'UInfixE', 'UInfixP', 'UInfixT', or 'PromotedUInfixT', -which stand for \"unresolved infix expression / pattern / type / promoted -constructor\", respectively. When the compiler is given a splice containing a -tree of @UInfixE@ applications such as - -> UInfixE -> (UInfixE e1 op1 e2) -> op2 -> (UInfixE e3 op3 e4) - -it will look up and the fixities of the relevant operators and -reassociate the tree as necessary. - - * trees will not be reassociated across 'ParensE', 'ParensP', or 'ParensT', - which are of use for parsing expressions like - - > (a + b * c) + d * e - - * 'InfixE', 'InfixP', 'InfixT', and 'PromotedInfixT' expressions are never - reassociated. - - * The 'UInfixE' constructor doesn't support sections. Sections - such as @(a *)@ have no ambiguity, so 'InfixE' suffices. For longer - sections such as @(a + b * c -)@, use an 'InfixE' constructor for the - outer-most section, and use 'UInfixE' constructors for all - other operators: - - > InfixE - > Just (UInfixE ...a + b * c...) - > op - > Nothing - - Sections such as @(a + b +)@ and @((a + b) +)@ should be rendered - into 'Exp's differently: - - > (+ a + b) ---> InfixE Nothing + (Just $ UInfixE a + b) - > -- will result in a fixity error if (+) is left-infix - > (+ (a + b)) ---> InfixE Nothing + (Just $ ParensE $ UInfixE a + b) - > -- no fixity errors - - * Quoted expressions such as - - > [| a * b + c |] :: Q Exp - > [p| a : b : c |] :: Q Pat - > [t| T + T |] :: Q Type - - will never contain 'UInfixE', 'UInfixP', 'UInfixT', 'PromotedUInfixT', - 'InfixT', 'PromotedInfixT, 'ParensE', 'ParensP', or 'ParensT' constructors. - --} - ----------------------------------------------------- -- -- The main syntax data types ===================================== libraries/template-haskell/Language/Haskell/TH/Lib.hs ===================================== @@ -395,3 +395,66 @@ mdoE = Internal.mdoE Nothing conP :: Quote m => Name -> [m Pat] -> m Pat conP n xs = Internal.conP n [] xs + + +-------------------------------------------------------------------------------- +-- * Constraint predicates (deprecated) + +{-# DEPRECATED classP "As of template-haskell-2.10, constraint predicates (Pred) are just types (Type), in keeping with ConstraintKinds. Please use 'conT' and 'appT'." #-} +classP :: Quote m => Name -> [m Type] -> m Pred +classP cla tys + = do + tysl <- sequenceA tys + pure (foldl AppT (ConT cla) tysl) + +{-# DEPRECATED equalP "As of template-haskell-2.10, constraint predicates (Pred) are just types (Type), in keeping with ConstraintKinds. Please see 'equalityT'." #-} +equalP :: Quote m => m Type -> m Type -> m Pred +equalP tleft tright + = do + tleft1 <- tleft + tright1 <- tright + eqT <- equalityT + pure (foldl AppT eqT [tleft1, tright1]) + +-------------------------------------------------------------------------------- +-- * Strictness queries (deprecated) +{-# DEPRECATED isStrict + ["Use 'bang'. See https://gitlab.haskell.org/ghc/ghc/wikis/migration/8.0. ", + "Example usage: 'bang noSourceUnpackedness sourceStrict'"] #-} +{-# DEPRECATED notStrict + ["Use 'bang'. See https://gitlab.haskell.org/ghc/ghc/wikis/migration/8.0. ", + "Example usage: 'bang noSourceUnpackedness noSourceStrictness'"] #-} +{-# DEPRECATED unpacked + ["Use 'bang'. See https://gitlab.haskell.org/ghc/ghc/wikis/migration/8.0. ", + "Example usage: 'bang sourceUnpack sourceStrict'"] #-} +isStrict, notStrict, unpacked :: Quote m => m Strict +isStrict = bang noSourceUnpackedness sourceStrict +notStrict = bang noSourceUnpackedness noSourceStrictness +unpacked = bang sourceUnpack sourceStrict + +{-# DEPRECATED strictType + "As of @template-haskell-2.11.0.0@, 'StrictType' has been replaced by 'BangType'. Please use 'bangType' instead." #-} +strictType :: Quote m => m Strict -> m Type -> m StrictType +strictType = bangType + +{-# DEPRECATED varStrictType + "As of @template-haskell-2.11.0.0@, 'VarStrictType' has been replaced by 'VarBangType'. Please use 'varBangType' instead." #-} +varStrictType :: Quote m => Name -> m StrictType -> m VarStrictType +varStrictType = varBangType + +-------------------------------------------------------------------------------- +-- * Specialisation pragmas (deprecated) + +{-# DEPRECATED pragSpecD "Please use 'pragSpecED' instead. 'pragSpecD' will be removed in GHC 9.18." #-} +pragSpecD :: Quote m => Name -> m Type -> Phases -> m Dec +pragSpecD n ty phases + = do + ty1 <- ty + pure $ PragmaD $ SpecialiseP n ty1 Nothing phases + +{-# DEPRECATED pragSpecInlD "Please use 'pragSpecInlED' instead. 'pragSpecInlD' will be removed in GHC 9.18." #-} +pragSpecInlD :: Quote m => Name -> m Type -> Inline -> Phases -> m Dec +pragSpecInlD n ty inline phases + = do + ty1 <- ty + pure $ PragmaD $ SpecialiseP n ty1 (Just inline) phases ===================================== libraries/template-haskell/Language/Haskell/TH/Quote.hs ===================================== @@ -19,12 +19,12 @@ module Language.Haskell.TH.Quote , namedDefaultQuasiQuoter , defaultQuasiQuoter -- * For backwards compatibility - ,dataToQa, dataToExpQ, dataToPatQ + , dataToQa, dataToExpQ, dataToPatQ ) where import GHC.Boot.TH.Syntax import GHC.Boot.TH.Quote -import GHC.Boot.TH.Lift +import Language.Haskell.TH.Syntax (dataToQa, dataToExpQ, dataToPatQ) -- | 'quoteFile' takes a 'QuasiQuoter' and lifts it into one that read ===================================== libraries/template-haskell/Language/Haskell/TH/Syntax.hs ===================================== @@ -1,6 +1,8 @@ {-# LANGUAGE MagicHash #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskellQuotes #-} -{-# LANGUAGE Safe #-} +{-# LANGUAGE Trustworthy #-} {-# LANGUAGE UnboxedTuples #-} module Language.Haskell.TH.Syntax ( @@ -190,19 +192,267 @@ module Language.Haskell.TH.Syntax ( nothingName, rightName, trueName, + -- * Notes + -- ** Unresolved Infix + -- $infix ) where import GHC.Boot.TH.Lift import GHC.Boot.TH.Syntax import System.FilePath +import Data.Data hiding (Fixity(..)) +import Data.List.NonEmpty (NonEmpty(..)) +import GHC.Lexeme ( startsVarSym, startsVarId ) -- This module completely re-exports 'GHC.Boot.TH.Syntax', -- and exports additionally functions that depend on filepath. +-- | +addForeignFile :: ForeignSrcLang -> String -> Q () +addForeignFile = addForeignSource +{-# DEPRECATED addForeignFile + "Use 'Language.Haskell.TH.Syntax.addForeignSource' instead" + #-} -- deprecated in 8.6 + -- | The input is a filepath, which if relative is offset by the package root. makeRelativeToProject :: FilePath -> Q FilePath makeRelativeToProject fp | isRelative fp = do root <- getPackageRoot return (root > fp) makeRelativeToProject fp = return fp + +trueName, falseName :: Name +trueName = 'True +falseName = 'False + +nothingName, justName :: Name +nothingName = 'Nothing +justName = 'Just + +leftName, rightName :: Name +leftName = 'Left +rightName = 'Right + +nonemptyName :: Name +nonemptyName = '(:|) + +----------------------------------------------------- +-- +-- Generic Lift implementations +-- +----------------------------------------------------- + +-- | 'dataToQa' is an internal utility function for constructing generic +-- conversion functions from types with 'Data' instances to various +-- quasi-quoting representations. See the source of 'dataToExpQ' and +-- 'dataToPatQ' for two example usages: @mkCon@, @mkLit@ +-- and @appQ@ are overloadable to account for different syntax for +-- expressions and patterns; @antiQ@ allows you to override type-specific +-- cases, a common usage is just @const Nothing@, which results in +-- no overloading. +dataToQa :: forall m a k q. (Quote m, Data a) + => (Name -> k) + -> (Lit -> m q) + -> (k -> [m q] -> m q) + -> (forall b . Data b => b -> Maybe (m q)) + -> a + -> m q +dataToQa mkCon mkLit appCon antiQ t = + case antiQ t of + Nothing -> + case constrRep constr of + AlgConstr _ -> + appCon (mkCon funOrConName) conArgs + where + funOrConName :: Name + funOrConName = + case showConstr constr of + "(:)" -> Name (mkOccName ":") + (NameG DataName + (mkPkgName "ghc-internal") + (mkModName "GHC.Internal.Types")) + con@"[]" -> Name (mkOccName con) + (NameG DataName + (mkPkgName "ghc-internal") + (mkModName "GHC.Internal.Types")) + con@('(':_) -> Name (mkOccName con) + (NameG DataName + (mkPkgName "ghc-internal") + (mkModName "GHC.Internal.Tuple")) + + -- Tricky case: see Note [Data for non-algebraic types] + fun@(x:_) | startsVarSym x || startsVarId x + -> mkNameG_v tyconPkg tyconMod fun + con -> mkNameG_d tyconPkg tyconMod con + + where + tycon :: TyCon + tycon = (typeRepTyCon . typeOf) t + + tyconPkg, tyconMod :: String + tyconPkg = tyConPackage tycon + tyconMod = tyConModule tycon + + conArgs :: [m q] + conArgs = gmapQ (dataToQa mkCon mkLit appCon antiQ) t + IntConstr n -> + mkLit $ IntegerL n + FloatConstr n -> + mkLit $ RationalL n + CharConstr c -> + mkLit $ CharL c + where + constr :: Constr + constr = toConstr t + + Just y -> y + + +{- Note [Data for non-algebraic types] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Class Data was originally intended for algebraic data types. But +it is possible to use it for abstract types too. For example, in +package `text` we find + + instance Data Text where + ... + toConstr _ = packConstr + + packConstr :: Constr + packConstr = mkConstr textDataType "pack" [] Prefix + +Here `packConstr` isn't a real data constructor, it's an ordinary +function. Two complications + +* In such a case, we must take care to build the Name using + mkNameG_v (for values), not mkNameG_d (for data constructors). + See #10796. + +* The pseudo-constructor is named only by its string, here "pack". + But 'dataToQa' needs the TyCon of its defining module, and has + to assume it's defined in the same module as the TyCon itself. + But nothing enforces that; #12596 shows what goes wrong if + "pack" is defined in a different module than the data type "Text". + -} + +-- | A typed variant of 'dataToExpQ'. +dataToCodeQ :: (Quote m, Data a) + => (forall b . Data b => b -> Maybe (Code m b)) + -> a -> Code m a +dataToCodeQ f = unsafeCodeCoerce . dataToExpQ (fmap unTypeCode . f) + +-- | 'dataToExpQ' converts a value to a 'Exp' representation of the +-- same value, in the SYB style. It is generalized to take a function +-- override type-specific cases; see 'liftData' for a more commonly +-- used variant. +dataToExpQ :: (Quote m, Data a) + => (forall b . Data b => b -> Maybe (m Exp)) + -> a + -> m Exp +dataToExpQ = dataToQa varOrConE litE (foldl appE) + where + -- Make sure that VarE is used if the Constr value relies on a + -- function underneath the surface (instead of a constructor). + -- See #10796. + varOrConE s = + case nameSpace s of + Just VarName -> return (VarE s) + Just (FldName {}) -> return (VarE s) + Just DataName -> return (ConE s) + _ -> error $ "Can't construct an expression from name " + ++ showName s + appE x y = do { a <- x; b <- y; return (AppE a b)} + litE c = return (LitE c) + +-- | A typed variant of 'liftData'. +liftDataTyped :: (Quote m, Data a) => a -> Code m a +liftDataTyped = dataToCodeQ (const Nothing) + +-- | 'liftData' is a variant of 'lift' in the 'Lift' type class which +-- works for any type with a 'Data' instance. +liftData :: (Quote m, Data a) => a -> m Exp +liftData = dataToExpQ (const Nothing) + +-- | 'dataToPatQ' converts a value to a 'Pat' representation of the same +-- value, in the SYB style. It takes a function to handle type-specific cases, +-- alternatively, pass @const Nothing@ to get default behavior. +dataToPatQ :: (Quote m, Data a) + => (forall b . Data b => b -> Maybe (m Pat)) + -> a + -> m Pat +dataToPatQ = dataToQa id litP conP + where litP l = return (LitP l) + conP n ps = + case nameSpace n of + Just DataName -> do + ps' <- sequence ps + return (ConP n [] ps') + _ -> error $ "Can't construct a pattern from name " + ++ showName n + +{- +Note [Unresolved infix] +~~~~~~~~~~~~~~~~~~~~~~~ +-} +{- $infix #infix# + +When implementing antiquotation for quasiquoters, one often wants +to parse strings into expressions: + +> parse :: String -> Maybe Exp + +But how should we parse @a + b * c@? If we don't know the fixities of +@+@ and @*@, we don't know whether to parse it as @a + (b * c)@ or @(a ++ b) * c@. + +In cases like this, use 'UInfixE', 'UInfixP', 'UInfixT', or 'PromotedUInfixT', +which stand for \"unresolved infix expression / pattern / type / promoted +constructor\", respectively. When the compiler is given a splice containing a +tree of @UInfixE@ applications such as + +> UInfixE +> (UInfixE e1 op1 e2) +> op2 +> (UInfixE e3 op3 e4) + +it will look up and the fixities of the relevant operators and +reassociate the tree as necessary. + + * trees will not be reassociated across 'ParensE', 'ParensP', or 'ParensT', + which are of use for parsing expressions like + + > (a + b * c) + d * e + + * 'InfixE', 'InfixP', 'InfixT', and 'PromotedInfixT' expressions are never + reassociated. + + * The 'UInfixE' constructor doesn't support sections. Sections + such as @(a *)@ have no ambiguity, so 'InfixE' suffices. For longer + sections such as @(a + b * c -)@, use an 'InfixE' constructor for the + outer-most section, and use 'UInfixE' constructors for all + other operators: + + > InfixE + > Just (UInfixE ...a + b * c...) + > op + > Nothing + + Sections such as @(a + b +)@ and @((a + b) +)@ should be rendered + into 'Exp's differently: + + > (+ a + b) ---> InfixE Nothing + (Just $ UInfixE a + b) + > -- will result in a fixity error if (+) is left-infix + > (+ (a + b)) ---> InfixE Nothing + (Just $ ParensE $ UInfixE a + b) + > -- no fixity errors + + * Quoted expressions such as + + > [| a * b + c |] :: Q Exp + > [p| a : b : c |] :: Q Pat + > [t| T + T |] :: Q Type + + will never contain 'UInfixE', 'UInfixP', 'UInfixT', 'PromotedUInfixT', + 'InfixT', 'PromotedInfixT, 'ParensE', 'ParensP', or 'ParensT' constructors. + +-} ===================================== libraries/template-haskell/tests/all.T ===================================== @@ -1,4 +1,4 @@ # difficult to test TH with profiling, because we have to build twice -test('dataToExpQUnit', [omit_ways(prof_ways), req_th], compile, ['-v0']) -test('dataToCodeQUnit', [omit_ways(prof_ways), req_th], compile, ['-v0']) +test('dataToExpQUnit', [omit_ways(prof_ways), req_th], compile, ['-package template-haskell -v0']) +test('dataToCodeQUnit', [omit_ways(prof_ways), req_th], compile, ['-package template-haskell -v0']) test('pragCompletePpr', [omit_ways(prof_ways), req_th], compile_and_run, ['']) ===================================== testsuite/tests/interface-stability/template-haskell-exports.stdout ===================================== @@ -1375,7 +1375,7 @@ module Language.Haskell.TH.Quote where quoteFile :: QuasiQuoter -> QuasiQuoter module Language.Haskell.TH.Syntax where - -- Safety: Safe + -- Safety: Trustworthy type AnnLookup :: * data AnnLookup = AnnLookupModule Module | AnnLookupName Name type AnnTarget :: * ===================================== testsuite/tests/quasiquotation/T4491/test.T ===================================== @@ -7,4 +7,4 @@ test('T4491', # the TH way only_ways([config.ghc_th_way]), ], - compile_and_run, ['']) + compile_and_run, ['-package template-haskell']) ===================================== testsuite/tests/th/Makefile ===================================== @@ -9,8 +9,8 @@ T2386: '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) -v0 -c T2386.hs T7445: - '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) -v0 -c T7445a.hs - '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) -v0 -c T7445.hs + '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) -package template-haskell -v0 -c T7445a.hs + '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) -package template-haskell -v0 -c T7445.hs HC_OPTS = -XTemplateHaskell -package template-haskell View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/91310ad0a7672dbe865f79a2f446d83... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/91310ad0a7672dbe865f79a2f446d83... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Marge Bot (@marge-bot)