packages feed

aihc-parser 2.0.0.0 → 3.0.0.0

raw patch · 38 files changed

+573/−292 lines, 38 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Aihc.Parser.Syntax: TBuiltinArrow :: TypeBuiltinCon
- Aihc.Parser.Syntax: TBuiltinCons :: TypeBuiltinCon
- Aihc.Parser.Syntax: TBuiltinList :: TypeBuiltinCon
- Aihc.Parser.Syntax: TBuiltinTuple :: Int -> TypeBuiltinCon
- Aihc.Parser.Syntax: data TypeBuiltinCon
- Aihc.Parser.Syntax: instance Control.DeepSeq.NFData Aihc.Parser.Syntax.TypeBuiltinCon
- Aihc.Parser.Syntax: instance Data.Data.Data Aihc.Parser.Syntax.TypeBuiltinCon
- Aihc.Parser.Syntax: instance GHC.Classes.Eq Aihc.Parser.Syntax.TypeBuiltinCon
- Aihc.Parser.Syntax: instance GHC.Generics.Generic Aihc.Parser.Syntax.TypeBuiltinCon
- Aihc.Parser.Syntax: instance GHC.Show.Show Aihc.Parser.Syntax.TypeBuiltinCon
+ Aihc.Parser.Syntax: BuiltinArrow :: BuiltinCon
+ Aihc.Parser.Syntax: BuiltinCons :: BuiltinCon
+ Aihc.Parser.Syntax: BuiltinList :: BuiltinCon
+ Aihc.Parser.Syntax: BuiltinTuple :: TupleFlavor -> Int -> BuiltinCon
+ Aihc.Parser.Syntax: EViewPat :: Expr -> Expr -> Expr
+ Aihc.Parser.Syntax: PBuiltinCon :: BuiltinCon -> [Type] -> [Pattern] -> Pattern
+ Aihc.Parser.Syntax: data BuiltinCon
+ Aihc.Parser.Syntax: instance Control.DeepSeq.NFData Aihc.Parser.Syntax.BuiltinCon
+ Aihc.Parser.Syntax: instance Data.Data.Data Aihc.Parser.Syntax.BuiltinCon
+ Aihc.Parser.Syntax: instance GHC.Classes.Eq Aihc.Parser.Syntax.BuiltinCon
+ Aihc.Parser.Syntax: instance GHC.Generics.Generic Aihc.Parser.Syntax.BuiltinCon
+ Aihc.Parser.Syntax: instance GHC.Show.Show Aihc.Parser.Syntax.BuiltinCon
- Aihc.Parser.Syntax: TBuiltinCon :: TypeBuiltinCon -> Type
+ Aihc.Parser.Syntax: TBuiltinCon :: BuiltinCon -> TypePromotion -> Type

Files

CHANGELOG.md view
@@ -6,6 +6,45 @@  ## [Unreleased] +## [3.0.0.0] - 2026-09-06++### Changed++- **Breaking:** Added the `BuiltinCon` type for the constructors that the+  grammar builds in: `(,)`, `(# , #)`, `(->)`, `[]`, and `(:)`. These+  constructors have no name that a scope can bind, so the AST no longer+  spells them as a `Name`. The type namespace uses `TBuiltinCon BuiltinCon+  TypePromotion` and the pattern namespace uses `PBuiltinCon BuiltinCon+  [Type] [Pattern]`. This replaces `TypeBuiltinCon`, `TBuiltinCon+  TypeBuiltinCon`, and `PTupleCon`.+  - A prefix tuple constructor in a pattern, such as `(,) a b`, parsed as a+    `PCon` whose name was only commas, such as `PCon ","+    [PVar "a", PVar "b"]`. The dedicated pattern parser now also accepts the+    prefix tuple constructor outside parentheses, for example in a `case`+    alternative.+  - An unboxed prefix tuple constructor in a type, such as `(# , #) Int+    Bool`, parsed as `TCon "(#,#)"`. The boxed form already had a dedicated+    constructor.+  - A promoted built-in constructor, such as `'[]`, `'(:)`, or `'(,)`,+    parsed as a `TCon` whose name was the surface syntax, such as `TCon "[]"+    Promoted`. `TBuiltinCon` now carries the promotion flag.+- **Breaking:** Added the `EViewPat` expression constructor for the+  view-pattern arrow. The parser made an `EInfix` with an operator named+  `->`, and `checkPattern` found the view pattern by a comparison against+  that name. No scope binds a term named `->`.+- The parser now rejects `'(->)`, which GHC also rejects. The arrow has no+  promoted form.+- The parser now rejects a reserved operator in a parenthesized expression:+  `(->)`, `(=>)`, `(::)`, `(=)`, `(|)`, `(<-)`, `(..)`, and `(@)`. These+  parsed as an `EVar` with the reserved operator as its name. GHC rejects+  each of them. `(-)` and `(:)` are unchanged.+- Made module parsing about 1.5x faster on the Stackage benchmark corpus and+  reduced allocation by a third. The context-item kind-signature lookahead now+  stops at declaration boundaries instead of scanning to the end of the+  module, the token stream memoizes each step so lookahead and backtracking+  no longer rerun the layout algorithm, and the lexer dispatches on the first+  character of each token.+ ## [2.0.0.0] - 2026-09-03  ### Changed
aihc-parser.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.8 name: aihc-parser-version: 2.0.0.0+version: 3.0.0.0 build-type: Simple license: Unlicense license-file: LICENSE
common/CppSupport.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE OverloadedStrings #-}- module CppSupport   ( preprocessForParser,     preprocessForParserIfEnabled,@@ -20,16 +18,13 @@     preprocess,   ) import Aihc.Hackage.Cpp qualified as HackageCpp+import Aihc.Hackage.Util (normalizeSourceForParser) import Aihc.Parser.Syntax (Extension (CPP), ExtensionSetting (..), ModuleHeaderPragmas (..)) import Aihc.Parser.Token (readModuleHeaderExtensions, readModuleHeaderPragmas) import Data.ByteString (ByteString)-import Data.Char (toLower) import Data.Functor.Identity (Identity (..), runIdentity)-import Data.Maybe (fromMaybe) import Data.Text (Text)-import Data.Text qualified as T import Data.Text.Encoding qualified as TE-import System.FilePath (takeExtension)  preprocessForParser :: (Monad m) => FilePath -> [Text] -> (IncludeRequest -> m (Maybe ByteString)) -> Text -> m Result preprocessForParser inputFile deps resolveInclude source =@@ -87,38 +82,3 @@         EnableExtension CPP -> True         DisableExtension CPP -> False         _ -> enabled--normalizeSourceForParser :: FilePath -> Text -> Text-normalizeSourceForParser inputFile =-  unliterateIfNeeded inputFile . stripLeadingBom--stripLeadingBom :: Text -> Text-stripLeadingBom txt =-  fromMaybe txt (T.stripPrefix "\xfeff" txt)--unliterateIfNeeded :: FilePath -> Text -> Text-unliterateIfNeeded inputFile source-  | map toLower (takeExtension inputFile) /= ".lhs" = source-  | otherwise =-      let ls = T.lines source-       in if any (\line -> T.strip line == "\\begin{code}") ls-            then T.unlines (unlitLatex False ls)-            else T.unlines (map unlitBirdLine ls)-  where-    -- Replace the leading '>' with a space instead of stripping it.-    -- This preserves original column positions, which is critical for-    -- layout-sensitive parsing when tabs are present.  Stripping "> "-    -- shifts columns by 2, but tab stops depend on absolute column-    -- position, so tab-aligned code and space-aligned code would end-    -- up at different columns after the shift.-    unlitBirdLine line =-      case T.stripPrefix ">" line of-        Just _rest -> " " <> _rest-        Nothing -> ""--    unlitLatex _ [] = []-    unlitLatex inCode (line : rest)-      | T.strip line == "\\begin{code}" = "" : unlitLatex True rest-      | T.strip line == "\\end{code}" = "" : unlitLatex False rest-      | inCode = line : unlitLatex inCode rest-      | otherwise = "" : unlitLatex inCode rest
common/HackageSupport.hs view
@@ -18,21 +18,20 @@   ) where -import Aihc.Cpp (Diagnostic (..), IncludeKind (..), IncludeRequest (..), Severity (..))+import Aihc.Cpp (Diagnostic (..), IncludeRequest, Severity (..)) import Aihc.Hackage.Cabal qualified as HC+import Aihc.Hackage.Cpp qualified as HCpp import Aihc.Hackage.Download qualified as HD import Aihc.Hackage.Types qualified as HT import Aihc.Hackage.Util qualified as HU import Aihc.Parser.Syntax qualified as Syntax import Data.ByteString qualified as BS-import Data.List (nub) import Data.Maybe (mapMaybe) import Data.Text (Text) import Data.Text qualified as T import Distribution.PackageDescription.Parsec (parseGenericPackageDescription, runParseResult) import Distribution.Types.GenericPackageDescription (GenericPackageDescription)-import System.Directory (doesFileExist)-import System.FilePath (isAbsolute, makeRelative, normalise, splitDirectories, takeDirectory, (</>))+import System.FilePath (takeDirectory)  -- | Download a Hackage package with verbose logging. downloadPackage :: String -> String -> IO FilePath@@ -133,53 +132,7 @@ readTextFileLenient = HU.readTextFileLenient  resolveIncludeBestEffort :: FilePath -> [FilePath] -> FilePath -> IncludeRequest -> IO (Maybe BS.ByteString)-resolveIncludeBestEffort packageRoot includeDirs currentFile req = do-  firstExisting <- firstExistingPath (includeCandidates packageRoot includeDirs currentFile req)-  case firstExisting of-    Nothing -> pure Nothing-    Just includeFile -> Just <$> BS.readFile includeFile--includeCandidates :: FilePath -> [FilePath] -> FilePath -> IncludeRequest -> [FilePath]-includeCandidates packageRoot includeDirs currentFile req =-  map normalise $ nub [dir </> includePath req | dir <- searchDirs]-  where-    includeDir = takeDirectory (includeFrom req)-    sourceRelDir = takeDirectory (makeRelative packageRoot currentFile)-    packageAncestors = ancestorDirs sourceRelDir-    localRoots =-      [ takeDirectory currentFile,-        packageRoot </> sourceRelDir,-        packageRoot </> includeDir-      ]-    systemRoots =-      includeDirs-        <> [ packageRoot </> "include",-             packageRoot </> "includes",-             packageRoot </> "cbits",-             packageRoot-           ]-    searchDirs =-      case includeKind req of-        IncludeLocal -> localRoots <> map (packageRoot </>) packageAncestors <> systemRoots-        IncludeSystem -> systemRoots <> localRoots <> map (packageRoot </>) packageAncestors--ancestorDirs :: FilePath -> [FilePath]-ancestorDirs path =-  case filter (not . null) (splitDirectories path) of-    [] -> []-    parts ->-      [ foldl (</>) "." (take n parts)-      | n <- [length parts, length parts - 1 .. 1]-      ]--firstExistingPath :: [FilePath] -> IO (Maybe FilePath)-firstExistingPath [] = pure Nothing-firstExistingPath (candidate : rest) = do-  let path = if isAbsolute candidate then candidate else normalise candidate-  exists <- doesFileExist path-  if exists-    then pure (Just path)-    else firstExistingPath rest+resolveIncludeBestEffort = HCpp.resolveIncludeBestEffort  diagToText :: Diagnostic -> Text diagToText diag =
src/Aihc/Parser.hs view
@@ -48,7 +48,6 @@ import Data.Word (Word8) import Prettyprinter (Doc, colon, defaultLayoutOptions, layoutPretty, pretty, vcat) import Prettyprinter.Render.String (renderString)-import Text.Megaparsec (runParser)  -- $setup -- >>> :set -XOverloadedStrings@@ -88,7 +87,7 @@ parseExpr :: ParserConfig -> Text -> ParseResult Expr parseExpr cfg input =   let ts = mkTokStream (parserSourceName cfg) (applyImpliedExtensions (parserExtensions cfg)) input-   in case runParser (exprParser <* eofTok) (parserSourceName cfg) ts of+   in case runTokStreamParser (exprParser <* eofTok) (parserSourceName cfg) ts of         Left bundle -> ParseErr (parseErrorBundleToSpannedText bundle)         Right expr -> ParseOk expr @@ -102,7 +101,7 @@ parsePattern :: ParserConfig -> Text -> ParseResult Pattern parsePattern cfg input =   let ts = mkTokStream (parserSourceName cfg) (applyImpliedExtensions (parserExtensions cfg)) input-   in case runParser (patternParser <* eofTok) (parserSourceName cfg) ts of+   in case runTokStreamParser (patternParser <* eofTok) (parserSourceName cfg) ts of         Left bundle -> ParseErr (parseErrorBundleToSpannedText bundle)         Right pat -> ParseOk pat @@ -116,7 +115,7 @@ parseSignatureType :: ParserConfig -> Text -> ParseResult Type parseSignatureType cfg input =   let ts = mkTokStream (parserSourceName cfg) (applyImpliedExtensions (parserExtensions cfg)) input-   in case runParser (typeSignatureParser <* eofTok) (parserSourceName cfg) ts of+   in case runTokStreamParser (typeSignatureParser <* eofTok) (parserSourceName cfg) ts of         Left bundle -> ParseErr (parseErrorBundleToSpannedText bundle)         Right ty -> ParseOk ty @@ -133,7 +132,7 @@ parseType :: ParserConfig -> Text -> ParseResult Type parseType cfg input =   let ts = mkTokStream (parserSourceName cfg) (applyImpliedExtensions (parserExtensions cfg)) input-   in case runParser (typeParser <* eofTok) (parserSourceName cfg) ts of+   in case runTokStreamParser (typeParser <* eofTok) (parserSourceName cfg) ts of         Left bundle -> ParseErr (parseErrorBundleToSpannedText bundle)         Right ty -> ParseOk ty @@ -144,7 +143,7 @@ parseDecl :: ParserConfig -> Text -> ParseResult Decl parseDecl cfg input =   let ts = mkTokStream (parserSourceName cfg) (applyImpliedExtensions (parserExtensions cfg)) input-   in case runParser (declParser <* eofTok) (parserSourceName cfg) ts of+   in case runTokStreamParser (declParser <* eofTok) (parserSourceName cfg) ts of         Left bundle -> ParseErr (parseErrorBundleToSpannedText bundle)         Right decl -> ParseOk decl @@ -168,7 +167,7 @@         modu <- moduleParser         errs <- drainParseErrors         pure (errs, modu)-   in case runParser parser (parserSourceName cfg) ts of+   in case runTokStreamParser parser (parserSourceName cfg) ts of         Left bundle ->           ( parseErrorBundleToSpannedText bundle,             Module
src/Aihc/Parser/Internal/CheckPattern.hs view
@@ -57,12 +57,12 @@   EList elems -> PList <$> traverse checkPattern elems   -- Unboxed sum   EUnboxedSum i n e -> PUnboxedSum i n <$> checkPattern e-  -- Infix: only constructor operators (starting with ':') or the view-pattern-  -- arrow @->@ are valid in patterns.+  -- View pattern: @expr -> pat@.+  EViewPat l r -> do+    rPat <- checkPattern r+    Right (PView l rPat)+  -- Infix: only constructor operators (starting with ':') are valid in patterns.   EInfix l op r-    | renderName op == "->" -> do-        rPat <- checkPattern r-        Right (PView l rPat)     | isConLikeOp op -> do         lPat <- checkPattern l         rPat <- checkPattern r@@ -80,6 +80,7 @@     xPat <- checkPattern x     case peelPatternAnn fPat of       PCon name typeArgs args -> Right (PCon name typeArgs (args ++ [xPat]))+      PBuiltinCon con typeArgs args -> Right (PBuiltinCon con typeArgs (args ++ [xPat]))       _ -> Left "invalid pattern: application of non-constructor"   -- Record construction -> record pattern   ERecordCon name fields wc -> do@@ -124,6 +125,7 @@     funPat <- checkPattern fun     case peelPatternAnn funPat of       PCon name typeArgs args -> Right (PCon name (typeArgs ++ [ty]) args)+      PBuiltinCon con typeArgs args -> Right (PBuiltinCon con (typeArgs ++ [ty]) args)       _ -> Left "unexpected type application in pattern"   ETHExpQuote {} -> Left "unexpected Template Haskell expression quote in pattern"   ETHTypedQuote {} -> Left "unexpected Template Haskell typed quote in pattern"@@ -150,23 +152,14 @@ checkTupleElement Nothing = Left "unexpected tuple section in pattern" checkTupleElement (Just e) = checkPattern e +-- | A tuple section with no fields, such as @(,)@ or @(#,,#)@, is the+-- prefix tuple constructor. tupleConstructorPattern :: TupleFlavor -> [Maybe Expr] -> Maybe Pattern tupleConstructorPattern fl elems   | null elems = Nothing-  | all isNothing elems = Just (PCon (tupleConstructorName fl (length elems)) [] [])+  | all isNothing elems = Just (PBuiltinCon (BuiltinTuple fl (length elems)) [] [])   | otherwise = Nothing -tupleConstructorName :: TupleFlavor -> Int -> Name-tupleConstructorName fl arity =-  qualifyName Nothing (mkUnqualifiedName NameConSym symbol)-  where-    symbol = case fl of-      Boxed -> tupleCommas-      Unboxed -> "#" <> tupleCommas <> "#"-    tupleCommas-      | arity == 1 = ""-      | otherwise = mconcat (replicate (arity - 1) ",")- -- | Check that a negated expression is a literal (for PNegLit patterns). checkNegLitPattern :: Expr -> Either Text Pattern checkNegLitPattern inner = case inner of@@ -183,13 +176,13 @@  -- | Try to interpret an expression as a view pattern @expr -> expr@. -- Returns 'Just' the corresponding 'PView' when the expression is an--- 'EInfix' with @->@; 'Nothing' otherwise.  Used by the 'EParen' case of+-- 'EViewPat'; 'Nothing' otherwise.  Used by the 'EParen' case of -- 'checkPattern' to strip the outer parentheses and produce @PView@ -- directly (matching the AST shape that the dedicated pattern parser -- produces). asViewPat :: Expr -> Maybe Pattern-asViewPat (EInfix l op r)-  | renderName op == "->" = case checkPattern r of-      Right rPat -> Just (PView l rPat)-      Left _ -> Nothing+asViewPat (EViewPat l r) =+  case checkPattern r of+    Right rPat -> Just (PView l rPat)+    Left _ -> Nothing asViewPat _ = Nothing
src/Aihc/Parser/Internal/Common.hs view
@@ -76,9 +76,9 @@   ) where -import Aihc.Parser.Lex (LayoutState (..), LexToken (..), LexTokenKind (..), closeImplicitLayoutContext)+import Aihc.Parser.Lex (LayoutState (..), LexToken (..), LexTokenKind (..), TokenOrigin (..), closeImplicitLayoutContext) import Aihc.Parser.Syntax-import Aihc.Parser.Types (ParserErrorComponent (..), TokStream (..), mkFoundToken, tokStreamExtensionSet)+import Aihc.Parser.Types (ParserErrorComponent (..), TokStream (..), mkFoundToken, setTokStreamLayout, setTokStreamPendingPragmas, tokStreamExtensionSet) import Control.Monad (guard) import Data.Char (isUpper) import Data.Functor (($>))@@ -248,12 +248,7 @@     (ignored, pragmaTok : rest)       | Just result <- f pragmaTok -> do           MP.updateParserState $ \st ->-            st-              { MP.stateInput =-                  (MP.stateInput st)-                    { tokStreamPendingPragmas = ignored <> rest-                    }-              }+            st {MP.stateInput = setTokStreamPendingPragmas (ignored <> rest) (MP.stateInput st)}           pure (Just result)       | otherwise -> pure Nothing     _ -> pure Nothing@@ -596,6 +591,10 @@      -- \| Lookahead: check if there's a `::` at the top bracket depth.     -- This avoids ambiguity with the bare constraint parser.+    --+    -- The scan stops at the first token that cannot be part of a context+    -- item. Without these stops, a context-less head such as+    -- @instance C T where ...@ scans through the whole instance body.     hasKindSignatureAtTopLevel :: TokParser Bool     hasKindSignatureAtTopLevel = MP.lookAhead (go 0)       where@@ -606,6 +605,7 @@             TkEOF -> pure False             TkReservedDoubleColon | depth == 0 -> pure True             TkReservedRightArrow | depth == 0 -> pure False+            TkReservedDoubleArrow | depth == 0 -> pure False             TkSpecialComma | depth == 0 -> pure False             TkSpecialLParen -> go (depth + 1)             TkSpecialRParen@@ -619,6 +619,29 @@             TkSpecialRBracket               | depth > 0 -> go (depth - 1)               | otherwise -> pure False+            TkSpecialLBrace+              | lexTokenOrigin tok == InsertedLayout -> pure False+            TkSpecialRBrace+              | lexTokenOrigin tok == InsertedLayout -> pure False+            TkSpecialSemicolon -> pure False+            TkReservedEquals -> pure False+            TkReservedPipe -> pure False+            TkReservedLeftArrow -> pure False+            TkKeywordWhere -> pure False+            TkKeywordDeriving -> pure False+            TkKeywordInstance -> pure False+            TkKeywordClass -> pure False+            TkKeywordData -> pure False+            TkKeywordNewtype -> pure False+            TkKeywordType -> pure False+            TkKeywordImport -> pure False+            TkKeywordModule -> pure False+            TkKeywordLet -> pure False+            TkKeywordIn -> pure False+            TkKeywordDo -> pure False+            TkKeywordOf -> pure False+            TkKeywordThen -> pure False+            TkKeywordElse -> pure False             _ -> go depth     constraintTypeParser = do       first <- constraintTypeAppParser@@ -910,13 +933,7 @@       MP.updateParserState         ( \s ->             let input = MP.stateInput s-             in s-                  { MP.stateInput =-                      input-                        { tokStreamLayoutState = laySt'',-                          tokStreamBuffer = inserted <> tokStreamBuffer input-                        }-                  }+             in s {MP.stateInput = setTokStreamLayout laySt'' (inserted <> tokStreamBuffer input) input}         )       pure True 
src/Aihc/Parser/Internal/Expr.hs view
@@ -103,10 +103,6 @@   | CmdArrAppLhsAtom   deriving (Eq) --- | The operator name used to represent @->@ in view-pattern expressions.-viewPatArrowName :: Name-viewPatArrowName = qualifyName Nothing (mkUnqualifiedName NameVarSym "->")- -- | Optionally consume a @->@ token and parse the right-hand side as a -- view-pattern expression.  Returns the original expression unchanged when -- no @->@ follows.@@ -114,7 +110,7 @@ maybeViewPattern lhs = do   mArrow <- MP.optional (expectedTok TkReservedRightArrow)   case mArrow of-    Just () -> EInfix lhs viewPatArrowName <$> texprParser+    Just () -> EViewPat lhs <$> texprParser     Nothing -> pure lhs  -- | Like 'exprParser' but also allows the view-pattern arrow @->@ at the@@ -647,6 +643,12 @@   withSpanAnn (EAnn . mkAnnotation) $     EVar <$> parens operatorExprNameParser +-- | Parse the operator inside a parenthesized operator expression such as+-- @(+)@, @(:)@, or @(-)@.+--+-- Reserved operators such as @->@, @=>@, @::@, @|@, @<-@, @=@, @..@, and @\@@+-- are grammar, not names.  They have no term-level meaning, so this parser+-- rejects them, in the same way as GHC. operatorExprNameParser :: TokParser Name operatorExprNameParser =   tokenSatisfy "operator" $ \tok ->@@ -655,16 +657,8 @@       TkConSym sym -> Just (qualifyName Nothing (mkUnqualifiedNameAt tok NameConSym sym))       TkQVarSym modName sym -> Just (mkNameAt tok (Just modName) NameVarSym sym)       TkQConSym modName sym -> Just (mkNameAt tok (Just modName) NameConSym sym)-      TkReservedAt -> Just (qualifyName Nothing (mkUnqualifiedNameAt tok NameVarSym "@"))       TkMinusOperator -> Just (qualifyName Nothing (mkUnqualifiedNameAt tok NameVarSym "-"))       TkReservedColon -> Just (qualifyName Nothing (mkUnqualifiedNameAt tok NameConSym ":"))-      TkReservedDoubleColon -> Just (qualifyName Nothing (mkUnqualifiedNameAt tok NameVarSym "::"))-      TkReservedEquals -> Just (qualifyName Nothing (mkUnqualifiedNameAt tok NameVarSym "="))-      TkReservedPipe -> Just (qualifyName Nothing (mkUnqualifiedNameAt tok NameVarSym "|"))-      TkReservedLeftArrow -> Just (qualifyName Nothing (mkUnqualifiedNameAt tok NameVarSym "<-"))-      TkReservedRightArrow -> Just (qualifyName Nothing (mkUnqualifiedNameAt tok NameVarSym "->"))-      TkReservedDoubleArrow -> Just (qualifyName Nothing (mkUnqualifiedNameAt tok NameVarSym "=>"))-      TkReservedDotDot -> Just (qualifyName Nothing (mkUnqualifiedNameAt tok NameVarSym ".."))       _ -> Nothing  rhsParser :: TokParser (Rhs Expr)
src/Aihc/Parser/Internal/FromTokens.hs view
@@ -33,11 +33,10 @@ import Aihc.Parser.Lex (LexToken) import Aihc.Parser.Syntax (Decl, Expr, ImportDecl, Module, ModuleHead, Pattern, Type) import Aihc.Parser.Types-import Text.Megaparsec (runParser)  runParserFromTokens :: TokParser a -> FilePath -> [LexToken] -> ParseResult a runParserFromTokens parser sourceName toks =-  case runParser parser sourceName (mkTokStreamFromTokens toks) of+  case runTokStreamParser parser sourceName (mkTokStreamFromTokens toks) of     Left bundle -> ParseErr (parseErrorBundleToSpannedText bundle)     Right parsed -> ParseOk parsed 
src/Aihc/Parser/Internal/Pattern.hs view
@@ -106,6 +106,10 @@       PAnn         (mkAnnotation NoSourceSpan)         (PCon name typeArgs (args <> [rhs]))+    PBuiltinCon con typeArgs args ->+      PAnn+        (mkAnnotation NoSourceSpan)+        (PBuiltinCon con typeArgs (args <> [rhs]))     _ -> lhs  -- | Parse an atomic pattern (@apat@ in the Haskell Report).@@ -128,20 +132,23 @@  nonAsApatParser :: TokParser Pattern nonAsApatParser = do-  thAny <- thAnyEnabled-  explicitNamespacesEnabled <- isExtensionEnabled ExplicitNamespaces-  requiredTypeArgumentsEnabled <- isExtensionEnabled RequiredTypeArguments-  typeAbstractionsEnabled <- isExtensionEnabled TypeAbstractions   tok <- lookAhead anySingle   case lexTokenKind tok of-    TkTypeApp-      | typeAbstractionsEnabled -> typeBinderPatternParser+    TkTypeApp -> do+      typeAbstractionsEnabled <- isExtensionEnabled TypeAbstractions+      if typeAbstractionsEnabled then typeBinderPatternParser else varOrConPatternParser     TkPrefixBang -> strictPatternParser     TkPrefixTilde -> irrefutablePatternParser-    TkKeywordType-      | explicitNamespacesEnabled || requiredTypeArgumentsEnabled -> explicitTypePatternParser+    TkKeywordType -> do+      explicitNamespacesEnabled <- isExtensionEnabled ExplicitNamespaces+      requiredTypeArgumentsEnabled <- isExtensionEnabled RequiredTypeArguments+      if explicitNamespacesEnabled || requiredTypeArgumentsEnabled+        then explicitTypePatternParser+        else varOrConPatternParser     TkQuasiQuote {} -> quasiQuotePatternParser-    TkTHSplice | thAny -> thSplicePatternParser+    TkTHSplice -> do+      thAny <- thAnyEnabled+      if thAny then thSplicePatternParser else varOrConPatternParser     TkKeywordUnderscore -> wildcardPatternParser     TkInteger {} -> literalPatternParser     TkFloat {} -> literalPatternParser@@ -359,6 +366,7 @@   case fmap lexTokenKind mNextTok of     Just nextKind       | nextKind == closeTok -> unitPatternParser tupleFlavor closeTok+      | nextKind == TkSpecialComma -> tupleConstructorPatternParser tupleFlavor closeTok       | tupleFlavor == Unboxed && nextKind == TkReservedPipe -> parseUnboxedSumPatLeadingBars closeTok     _ -> do       -- For boxed parens, try parsing as a top-level view pattern first.@@ -406,6 +414,14 @@       expectedTok closeTok       pure (PTuple tupleFlavor []) +    -- Parse the prefix tuple constructor @(,)@, @(,,)@, or @(#,#)@.+    -- The opening delimiter is already consumed. The arity is the+    -- number of commas plus one.+    tupleConstructorPatternParser tupleFlavor closeTok = do+      commas <- MP.some (expectedTok TkSpecialComma)+      expectedTok closeTok+      pure (PBuiltinCon (BuiltinTuple tupleFlavor (length commas + 1)) [] [])+     -- Try to parse the paren content as a view pattern: expr -> pat.     -- Uses exprParser which stops before '->', then checks for the arrow.     -- Returns Nothing if the content is not a view pattern.@@ -560,5 +576,6 @@ isPatternAppHead pat =   case peelPatternAnn pat of     PCon {} -> True+    PBuiltinCon {} -> True     PVar name -> isConLikeNameType (unqualifiedNameType name)     _ -> False
src/Aihc/Parser/Internal/Type.hs view
@@ -469,8 +469,8 @@   expectedTok TkSpecialRParen   pure $     case (nameQualifier op, nameType op, nameText op) of-      (Nothing, NameVarSym, "->") -> TBuiltinCon TBuiltinArrow-      (Nothing, NameConSym, ":") -> TBuiltinCon TBuiltinCons+      (Nothing, NameVarSym, "->") -> TBuiltinCon BuiltinArrow Unpromoted+      (Nothing, NameConSym, ":") -> TBuiltinCon BuiltinCons Unpromoted       _ -> TCon op Unpromoted  typeQuasiQuoteParser :: TokParser Type@@ -512,7 +512,7 @@   expectedTok TkSpecialLBracket   mClosed <- MP.optional (expectedTok TkSpecialRBracket)   case mClosed of-    Just () -> pure (TBuiltinCon TBuiltinList)+    Just () -> pure (TBuiltinCon BuiltinList Unpromoted)     Nothing -> do       elems <- typeParser `MP.sepBy1` expectedTok TkSpecialComma       expectedTok TkSpecialRBracket@@ -532,11 +532,7 @@       moreCommas <- MP.many (expectedTok TkSpecialComma)       expectedTok closeTok       let arity = 2 + length moreCommas-      case tupleFlavor of-        Boxed -> pure (TBuiltinCon (TBuiltinTuple arity))-        Unboxed -> do-          let tupleConName = "(#" <> T.replicate (arity - 1) "," <> "#)"-          pure (TCon (qualifyName Nothing (mkUnqualifiedName NameConId tupleConName)) Unpromoted)+      pure (TBuiltinCon (BuiltinTuple tupleFlavor arity) Unpromoted)      parenthesizedTypeOrTupleParser tupleFlavor closeTok = do       first <- typeParser@@ -575,20 +571,10 @@       | Just inner <- markTypePromoted sub ->           Just (TAnn ann inner)     TCon name _ -> Just (TCon name Promoted)-    TBuiltinCon con -> Just (promoteBuiltinCon con)+    -- @'(->)@ is not valid syntax: the arrow has no promoted form.+    TBuiltinCon BuiltinArrow _ -> Nothing+    TBuiltinCon con _ -> Just (TBuiltinCon con Promoted)     TList _ elems -> Just (TList Promoted elems)     TTuple tupleFlavor _ elems -> Just (TTuple tupleFlavor Promoted elems)     TTypeApp fn arg -> TTypeApp <$> markTypePromoted fn <*> pure arg     _ -> Nothing--promoteBuiltinCon :: TypeBuiltinCon -> Type-promoteBuiltinCon con =-  TCon-    ( qualifyName Nothing $-        case con of-          TBuiltinTuple arity -> mkUnqualifiedName NameConId ("(" <> T.replicate (max 0 (arity - 1)) "," <> ")")-          TBuiltinArrow -> mkUnqualifiedName NameVarSym "->"-          TBuiltinList -> mkUnqualifiedName NameConId "[]"-          TBuiltinCons -> mkUnqualifiedName NameConSym ":"-    )-    Promoted
src/Aihc/Parser/Lex.hs view
@@ -75,6 +75,7 @@ import Data.Maybe (fromMaybe, isJust) import Data.Text (Text, pattern Empty, pattern (:<)) import Data.Text qualified as T+import Data.Text.Unsafe qualified as TU  lexTokens :: Text -> [LexToken] lexTokens = lexTokensWithSourceNameAndExtensions "<input>" []@@ -139,7 +140,10 @@             Empty -> SkipDone st             c :< _               | isHaskellWhitespace c ->-                  go (markHadTrivia (consumeWhile isHaskellWhitespace st))+                  go (skipWhitespace st)+              -- Only '-', '{', and '#' can start trivia; other characters+              -- begin a token.+              | c /= '-' && c /= '{' && c /= '#' -> SkipDone st             _               | Just rest <- T.stripPrefix "--" inp,                 isLineComment rest ->@@ -195,6 +199,34 @@  nextToken :: LexerEnv -> LexerState -> (LexToken, LexerState) nextToken env st =+  -- Dispatch on the first character to skip alternatives that cannot match.+  -- Each branch keeps the relative order of the general chain below, so the+  -- token produced is the same as the one the chain would produce.+  case lexerInput st of+    c :< _+      | isAsciiLower c || isAsciiUpper c || c == '_' ->+          fromMaybe (lexErrorToken st "unexpected character") (lexIdentifier env st)+      | isDigit c ->+          fromMaybe (lexErrorToken st "unexpected character") $+            lexHexFloat env st+              <|> lexFloat env st+              <|> lexIntBase env st+              <|> lexInt env st+      | c == '(' || c == ')' || c == ']' || c == '}' || c == ',' || c == ';' || c == '`' ->+          fromMaybe (lexErrorToken st "unexpected character") (lexSymbol env st)+      | isPlainOperatorStart c ->+          fromMaybe (lexErrorToken st "unexpected character") (lexOperator env st)+    _ -> nextTokenGeneral env st++-- | Symbolic characters that only 'lexOperator' can start a token with.+-- The characters handled by earlier alternatives in 'nextTokenGeneral'+-- (@-@, @!@, @~@, @%@, @@@, @#@, @$@, @?@, @|@, @'@, @"@) are excluded.+isPlainOperatorStart :: Char -> Bool+isPlainOperatorStart c =+  c == '=' || c == '<' || c == '>' || c == '.' || c == '*' || c == '+' || c == '&' || c == '^' || c == '/' || c == '\\' || c == ':'++nextTokenGeneral :: LexerEnv -> LexerState -> (LexToken, LexerState)+nextTokenGeneral env st =   -- Inline chain of alternatives with no intermediate list or closure allocation.   -- (<|>) for Maybe short-circuits on the first Just without allocating.   fromMaybe (lexErrorToken st "unexpected character") $@@ -265,8 +297,8 @@       | isIdentStart c ->           let hasMagicHash = hasExt MagicHash env               (seg, rest0) = consumeIdentTail hasMagicHash rest-              firstChunk = T.take (1 + T.length seg) (lexerInput st)-              (consumed, rest1, isQualified) = gatherQualified hasMagicHash firstChunk rest0+              firstChunk = TU.takeWord8 (utf8CharWidth c + TU.lengthWord8 seg) (lexerInput st)+              (consumed, rest1, isQualified) = gatherQualified hasMagicHash False firstChunk rest0            in case (isQualified || isConIdStart c, rest1) of                 (True, '.' :< dotRest@(opChar :< _))                   | isSymbolicOpChar opChar ->@@ -285,17 +317,18 @@                    in Just (mkToken st st' consumed kind, st')     _ -> Nothing   where-    gatherQualified :: Bool -> Text -> Text -> (Text, Text, Bool)-    gatherQualified hasMH acc chars =+    -- The Bool accumulator records whether a qualifier segment was added.+    gatherQualified :: Bool -> Bool -> Text -> Text -> (Text, Text, Bool)+    gatherQualified hasMH qualified acc chars =       case chars of         '.' :< dotRest@(c' :< more)           | isIdentStart c',             not (T.isSuffixOf "#" acc),             isConIdStart (T.head acc) ->               let (seg, rest) = consumeIdentTail hasMH more-                  segWithHead = T.take (1 + T.length seg) dotRest-               in gatherQualified hasMH (acc <> "." <> segWithHead) rest-        _ -> (acc, chars, T.any (== '.') acc)+                  segWithHead = TU.takeWord8 (utf8CharWidth c' + TU.lengthWord8 seg) dotRest+               in gatherQualified hasMH True (acc <> "." <> segWithHead) rest+        _ -> (acc, chars, qualified)      -- Split a qualified identifier into (module part, name part).     -- E.g. "Data.Maybe." ++ "++" -> ("Data.Maybe", "++")
src/Aihc/Parser/Lex/Types.hs view
@@ -38,6 +38,8 @@     advanceChars,     advanceN,     consumeWhile,+    skipWhitespace,+    utf8CharWidth,     tokenStartCol,     virtualSymbolToken,     isSymbolicOpChar,@@ -53,6 +55,7 @@ import Data.Data (Data) import Data.Text (Text) import Data.Text qualified as T+import Data.Text.Unsafe qualified as TU import GHC.Generics (Generic)  data LexTokenKind@@ -375,8 +378,7 @@  advanceChars :: Text -> LexerState -> LexerState advanceChars consumed st =-  let !n = T.length consumed-      go (!line, !col, !byteOff, !atLineStart) ch =+  let go (!line, !col, !byteOff, !atLineStart) ch =         case ch of           '\n' -> (line + 1, 1, byteOff + 1, True)           '\t' ->@@ -389,7 +391,9 @@       (!finalLine, !finalCol, !finalByteOff, !finalAtLineStart) =         T.foldl' go (lexerLine st, lexerCol st, lexerByteOffset st, lexerAtLineStart st) consumed    in st-        { lexerInput = T.drop n (lexerInput st),+        { -- The consumed text is a prefix of the input, so dropping its UTF-8+          -- byte length avoids a second scan of the characters.+          lexerInput = TU.dropWord8 (TU.lengthWord8 consumed) (lexerInput st),           lexerLine = finalLine,           lexerCol = finalCol,           lexerByteOffset = finalByteOff,@@ -403,6 +407,37 @@ consumeWhile f st =   let consumed = T.takeWhile f (lexerInput st)    in advanceChars consumed st++-- | Skip leading Haskell whitespace in one pass and record that trivia was+-- seen. Equivalent to @markHadTrivia (consumeWhile isHaskellWhitespace)@ but+-- without the intermediate slice and the second lexer-state copy.+skipWhitespace :: LexerState -> LexerState+skipWhitespace st =+  let input = lexerInput st+      !len = TU.lengthWord8 input+      go !i !line !col !byteOff !atLineStart+        | i >= len = finish i line col byteOff atLineStart+        | otherwise =+            let TU.Iter ch d = TU.iter input i+             in case ch of+                  '\n' -> go (i + d) (line + 1) 1 (byteOff + 1) True+                  '\t' ->+                    let nextTabStop = 8 - ((col - 1) `mod` 8)+                     in go (i + d) line (col + nextTabStop) (byteOff + 1) atLineStart+                  ' ' -> go (i + d) line (col + 1) (byteOff + 1) atLineStart+                  _+                    | isSpace ch -> go (i + d) line (col + 1) (byteOff + d) atLineStart+                    | otherwise -> finish i line col byteOff atLineStart+      finish i line col byteOff atLineStart =+        st+          { lexerInput = TU.dropWord8 i input,+            lexerLine = line,+            lexerCol = col,+            lexerByteOffset = byteOff,+            lexerAtLineStart = atLineStart,+            lexerHadTrivia = True+          }+   in go 0 (lexerLine st) (lexerCol st) (lexerByteOffset st) (lexerAtLineStart st)  tokenStartCol :: LexToken -> Int tokenStartCol tok =
src/Aihc/Parser/Parens.hs view
@@ -654,6 +654,10 @@ typedPatternBindLhsNeedsParens (PAnn _ sub) = typedPatternBindLhsNeedsParens sub typedPatternBindLhsNeedsParens (PCon name typeArgs args) =   not (null typeArgs) || not (null args) || isNothing (nameQualifier name)+-- An unapplied built-in constructor already carries its own delimiters, so+-- @let (,) :: ty = e@ parses without more parentheses.+typedPatternBindLhsNeedsParens (PBuiltinCon _ typeArgs args) =+  not (null typeArgs) || not (null args) typedPatternBindLhsNeedsParens _ = False  addMatchParens :: UnqualifiedName -> Match -> Match@@ -812,8 +816,9 @@ bangTypeNeedsPrefixParens (TParen _) = False bangTypeNeedsPrefixParens TStar {} = True bangTypeNeedsPrefixParens (TCon _ Promoted) = True-bangTypeNeedsPrefixParens (TBuiltinCon TBuiltinCons) = True-bangTypeNeedsPrefixParens (TBuiltinCon _) = False+bangTypeNeedsPrefixParens (TBuiltinCon BuiltinCons Unpromoted) = True+bangTypeNeedsPrefixParens (TBuiltinCon _ Promoted) = True+bangTypeNeedsPrefixParens (TBuiltinCon _ _) = False bangTypeNeedsPrefixParens TImplicitParam {} = True bangTypeNeedsPrefixParens TSplice {} = True -- Compound types: the first rendered character comes from the head/lhs.@@ -866,7 +871,7 @@ infixConOperandNeedsParens (TTuple Unboxed _ _) = False infixConOperandNeedsParens (TUnboxedSum {}) = True infixConOperandNeedsParens (TList _ []) = True-infixConOperandNeedsParens (TBuiltinCon TBuiltinList) = True+infixConOperandNeedsParens (TBuiltinCon BuiltinList _) = True infixConOperandNeedsParens (TInfix {}) = True -- Application head determines what the parser sees first. infixConOperandNeedsParens (TApp f _) = infixConOperandNeedsParens f@@ -1118,6 +1123,9 @@             op             (addExprParensIn (CtxInfixRhs (prec == 1)) rhs)         )+    EViewPat viewExpr rhs ->+      -- The view-pattern arrow only parses directly inside parentheses.+      wrapExpr (prec > 0) (EViewPat (addExprParens viewExpr) (addExprParens rhs))     ENegate inner ->       wrapExpr (prec > 2) (ENegate (addNegateParens inner))     ESectionL lhs op ->@@ -1703,6 +1711,8 @@     PUnboxedSum altIdx arity inner -> PUnboxedSum altIdx arity (addPatternInUnboxedSum altIdx inner)     PList elems -> PList (map addPatternInDelimited elems)     PCon con typeArgs args -> PCon con (map (addTypeIn CtxTypeAtom) typeArgs) (map addPatternAtomParens args)+    PBuiltinCon con typeArgs args ->+      PBuiltinCon con (map (addTypeIn CtxTypeAtom) typeArgs) (map addPatternAtomParens args)     PInfix lhs op rhs -> PInfix (addPatternInfixOperandParens lhs) op (addPatternInfixRhsOperandParens rhs)     PView viewExpr inner ->       wrapPat True (PView (addViewExprParens viewExpr) (addPatternViewInnerParens inner))@@ -1916,6 +1926,7 @@     PSplice {} -> addPatternParens pat     PRecord {} -> addPatternParens pat     PCon _ [] [] -> addPatternParens pat+    PBuiltinCon _ [] [] -> addPatternParens pat     PInfix {} -> wrapPat True (addPatternParens pat)     _ -> wrapPat True (addPatternParens pat) @@ -1930,6 +1941,7 @@     PAnn ann sub -> PAnn ann (addPatternInfixOperandParens sub)     PNegLit _ -> addPatternParens pat     PCon {} -> addPatternParens pat+    PBuiltinCon {} -> addPatternParens pat     PInfix {} -> addPatternParens pat     _ -> addPatternAtomParens pat @@ -1944,6 +1956,7 @@     -- directly as either operand of an infix pattern.     PNegLit {} -> addPatternParens pat     PCon {} -> addPatternParens pat+    PBuiltinCon {} -> addPatternParens pat     PInfix {} -> wrapPat True (addPatternParens pat)     _ -> addPatternAtomParens pat @@ -1956,6 +1969,8 @@ addArrowBndrPatternParens p@(PInfix {}) = wrapPat True (addPatternParens p) addArrowBndrPatternParens p@(PCon _ (_ : _) _) = wrapPat True (addPatternParens p) addArrowBndrPatternParens p@(PCon _ [] (_ : _)) = wrapPat True (addPatternParens p)+addArrowBndrPatternParens p@(PBuiltinCon _ (_ : _) _) = wrapPat True (addPatternParens p)+addArrowBndrPatternParens p@(PBuiltinCon _ [] (_ : _)) = wrapPat True (addPatternParens p) addArrowBndrPatternParens pat = addPatternParens pat  -- | Add parens for a pattern in function-head argument position.@@ -1969,6 +1984,8 @@     PTypeSyntax {} -> wrapPat True (addPatternParens pat)     PCon _ typeArgs args       | not (null typeArgs) || not (null args) -> wrapPat True (addPatternParens pat)+    PBuiltinCon _ typeArgs args+      | not (null typeArgs) || not (null args) -> wrapPat True (addPatternParens pat)     PTypeSig inner@(PVar {}) ty ->       wrapPat True (PTypeSig (addPatternInfixOperandParens inner) (addSignatureTypeParens ty))     PTypeSig {} -> wrapPat True (addPatternParens pat)@@ -2002,6 +2019,7 @@     PNegLit {} -> wrapPat True (addPatternParens pat)     PTypeSyntax {} -> wrapPat True (addPatternParens pat)     PCon _ (_ : _) [] -> wrapPat True (addPatternParens pat)+    PBuiltinCon _ (_ : _) [] -> wrapPat True (addPatternParens pat)     PAs {} -> addPatternParens pat     PStrict {} -> wrapPat True (addPatternParens pat)     PIrrefutable {} -> wrapPat True (addPatternParens pat)
src/Aihc/Parser/Pretty.hs view
@@ -454,7 +454,9 @@             | T.any (== '\'') rendered = "' "             | otherwise = "'"        in if promoted == Promoted then promoteTick <> base else base-    TBuiltinCon con -> prettyTypeBuiltinCon con+    TBuiltinCon con promoted ->+      let base = prettyBuiltinCon con+       in if promoted == Promoted then "'" <> base else base     TImplicitParam name inner -> pretty name <+> "::" <+> prettyType inner     TTypeLit lit -> prettyTypeLiteral lit     TStar spelling -> pretty spelling@@ -505,13 +507,19 @@ prettyArrowKind ArrowLinear = "%1" <+> "->" prettyArrowKind (ArrowExplicit ty) = "%" <> prettyType ty <+> "->" -prettyTypeBuiltinCon :: TypeBuiltinCon -> Doc ann-prettyTypeBuiltinCon con =+-- | Print a built-in constructor such as @(,)@, @(# , #)@, @(->)@, @[]@,+-- or @(:)@.+prettyBuiltinCon :: BuiltinCon -> Doc ann+prettyBuiltinCon con =   case con of-    TBuiltinTuple arity -> parens (pretty (T.replicate (max 0 (arity - 1)) ","))-    TBuiltinArrow -> "(->)"-    TBuiltinList -> "[]"-    TBuiltinCons -> "(:)"+    BuiltinTuple tupleFlavor arity ->+      let commas = mconcat (replicate (max 0 (arity - 1)) comma)+       in case tupleFlavor of+            Boxed -> parens commas+            Unboxed -> "(#" <> commas <> "#)"+    BuiltinArrow -> "(->)"+    BuiltinList -> "[]"+    BuiltinCons -> "(:)"  prettyContext :: [Type] -> Doc ann prettyContext constraints =@@ -550,6 +558,8 @@        in hsep ["(#", prettyBarSeparated slots, "#)"]     PList elems -> brackets (hsep (punctuate comma (map prettyPattern elems)))     PCon con typeArgs args -> hsep ([prettyPrefixName con] <> map prettyInvisibleTypeArg typeArgs <> map prettyPattern args)+    PBuiltinCon con typeArgs args ->+      hsep ([prettyBuiltinCon con] <> map prettyInvisibleTypeArg typeArgs <> map prettyPattern args)     PInfix lhs op rhs -> prettyPattern lhs <+> prettyNameInfixOp op <+> prettyPattern rhs     PView viewExpr inner ->       prettyExpr viewExpr <> nest 1 (hardline <> "->" <+> prettyPattern inner)@@ -1184,6 +1194,8 @@       "\\" <> "cases" <> prettyCaseLayout (map prettyLambdaCaseAlt alts)     EInfix lhs op rhs ->       nest 2 (prettyExpr lhs) <> nest 1 (hardline <> prettyNameInfixOp op <+> prettyExpr rhs)+    EViewPat viewExpr rhs ->+      prettyExpr viewExpr <> nest 1 (hardline <> "->" <+> prettyExpr rhs)     ENegate inner -> "-" <+> prettyExprAtStatementStart inner     ESectionL lhs op ->       nest 2 (prettyExpr lhs) <> nest 1 (hardline <> " " <> prettyNameInfixOp op)@@ -1277,6 +1289,7 @@     Boxed -> parens inner     Unboxed -> hsep ["(#", inner, "#)"] +-- | Print the prefix tuple constructor for the given arity: @(,)@ or @(#,#)@. prettyBinding :: RecordField Expr -> Doc ann prettyBinding field =   if recordFieldPun field
src/Aihc/Parser/Shorthand.hs view
@@ -639,7 +639,10 @@       "TCon"         <+> docName name         <> (if promoted == Promoted then " Promoted" else "")-    TBuiltinCon con -> "TBuiltinCon" <+> pretty (show con)+    TBuiltinCon con promoted ->+      "TBuiltinCon"+        <+> hsep (docBuiltinCon con)+        <> (if promoted == Promoted then " Promoted" else "")     TImplicitParam name inner -> "TImplicitParam" <+> docText name <+> parens (docType inner)     TTypeLit lit -> "TTypeLit" <+> docTypeLiteral lit     TStar {} -> "TStar"@@ -796,6 +799,24 @@                       )                   )               )+    PBuiltinCon con typeArgs args ->+      case typeArgs of+        [] -> "PBuiltinCon" <+> hsep (docBuiltinCon con <> [brackets (hsep (punctuate comma (map docPattern args)))])+        _ ->+          "PBuiltinCon"+            <+> hsep+              ( docBuiltinCon con+                  <> [ braces+                         ( hsep+                             ( punctuate+                                 comma+                                 ( listField docType typeArgs+                                     <> listField docPattern args+                                 )+                             )+                         )+                     ]+              )     PInfix lhs op rhs -> "PInfix" <+> parens (docPattern lhs) <+> docName op <+> parens (docPattern rhs)     PView expr inner -> "PView" <+> parens (docExpr expr) <+> parens (docPattern inner)     PAs name inner -> "PAs" <+> docUnqualifiedName name <+> parens (docPattern inner)@@ -809,13 +830,24 @@  docPatternTupleFields :: TupleFlavor -> [Pattern] -> [Doc ann] docPatternTupleFields tupleFlavor elems =-  flavorFields <> [brackets (hsep (punctuate comma (map docPattern elems)))]-  where-    flavorFields =-      case tupleFlavor of-        Boxed -> []-        _ -> [pretty (show tupleFlavor)]+  docTupleFlavor tupleFlavor <> [brackets (hsep (punctuate comma (map docPattern elems)))] +-- | The shorthand omits the default 'Boxed' flavor.+-- | Render a built-in constructor as its shorthand tag.+docBuiltinCon :: BuiltinCon -> [Doc ann]+docBuiltinCon con =+  case con of+    BuiltinTuple tupleFlavor arity -> ["BuiltinTuple"] <> docTupleFlavor tupleFlavor <> [pretty arity]+    BuiltinArrow -> ["BuiltinArrow"]+    BuiltinList -> ["BuiltinList"]+    BuiltinCons -> ["BuiltinCons"]++docTupleFlavor :: TupleFlavor -> [Doc ann]+docTupleFlavor tupleFlavor =+  case tupleFlavor of+    Boxed -> []+    _ -> [pretty (show tupleFlavor)]+ docLiteral :: Literal -> Doc ann docLiteral lit =   case peelLiteralAnn lit of@@ -858,6 +890,7 @@     ELambdaCase alts -> "ELambdaCase" <+> brackets (hsep (punctuate comma (map docCaseAlt alts)))     ELambdaCases alts -> "ELambdaCases" <+> brackets (hsep (punctuate comma (map docLambdaCaseAlt alts)))     EInfix lhs op rhs -> "EInfix" <+> parens (docExpr lhs) <+> docName op <+> parens (docExpr rhs)+    EViewPat viewExpr rhs -> "EViewPat" <+> parens (docExpr viewExpr) <+> parens (docExpr rhs)     ENegate inner -> "ENegate" <+> parens (docExpr inner)     ESectionL lhs op -> "ESectionL" <+> parens (docExpr lhs) <+> docName op     ESectionR op rhs -> "ESectionR" <+> docName op <+> parens (docExpr rhs)
src/Aihc/Parser/Syntax.hs view
@@ -15,6 +15,7 @@     ArrAppType (..),     BangType (..),     BinderName,+    BuiltinCon (..),     BinderHead (..),     CallConv (..),     CaseAlt (..),@@ -92,7 +93,6 @@     FloatType (..),     NumericType (..),     TypeLiteral (..),-    TypeBuiltinCon (..),     TypePromotion (..),     ForallVis (..),     ForallTelescope (..),@@ -1247,6 +1247,9 @@     PList [Pattern]   | -- | @Just x@ or @Proxy \@Type@     PCon Name [Type] [Pattern]+  | -- | @(,) x y@ or @(#,#) x y@: a built-in constructor applied to+    -- invisible type arguments and patterns.+    PBuiltinCon BuiltinCon [Type] [Pattern]   | -- | @x :+: y@     PInfix Pattern Name Pattern   | -- | @(view -> pat)@@@ -1319,8 +1322,8 @@     TVar UnqualifiedName   | -- | @Maybe@ or @'Just@     TCon Name TypePromotion-  | -- | @(,)@, @(->)@, @[]@, or @(:)@-    TBuiltinCon TypeBuiltinCon+  | -- | @(,)@, @(# , #)@, @(->)@, @[]@, @(:)@, or a promoted form such as @'[]@+    TBuiltinCon BuiltinCon TypePromotion   | -- | @(?x :: Int) => Int@     TImplicitParam Text Type   | -- | @1@, @"x"@, or @'c'@ at the type level.@@ -1358,17 +1361,26 @@     TWildcard   deriving (Data, Eq, Show, Generic, NFData) --- | Built-in type constructors that have dedicated surface syntax.--- Examples: @(,)@, @(->)@, @[]@, and @(:)@.-data TypeBuiltinCon-  = -- | An @n@-tuple constructor like @(,)@ or @(,,)@.-    TBuiltinTuple Int+-- | A constructor that the grammar builds in.+--+-- These constructors have dedicated surface syntax and no name that a scope+-- can bind, so they get their own representation instead of a 'Name'.+-- Examples: @(,)@, @(# , #)@, @(->)@, @[]@, and @(:)@.+--+-- The same type serves the type namespace ('TBuiltinCon') and the pattern+-- namespace ('PBuiltinCon').  Patterns use 'BuiltinTuple' only; the other+-- constructors have ordinary pattern syntax (@[]@, @(:)@) or no term-level+-- form at all (@(->)@).+data BuiltinCon+  = -- | An @n@-tuple constructor such as @(,)@, @(,,)@, or @(# , #)@.+    -- The 'Int' is the arity, which is the number of commas plus one.+    BuiltinTuple TupleFlavor Int   | -- | @(->)@-    TBuiltinArrow+    BuiltinArrow   | -- | @[]@-    TBuiltinList+    BuiltinList   | -- | @(:)@-    TBuiltinCons+    BuiltinCons   deriving (Data, Eq, Show, Generic, NFData)  typeAnnSpan :: SourceSpan -> Type -> Type@@ -2020,6 +2032,10 @@     ELambdaCases [LambdaCaseAlt]   | -- | @a + b@     EInfix Expr Name Expr+  | -- | @f -> pat@ inside parentheses: the view-pattern arrow.+    -- The arrow is grammar, not an operator that a scope can bind, so it+    -- gets its own constructor.  'checkPattern' turns this into 'PView'.+    EViewPat Expr Expr   | -- | @-x@     ENegate Expr   | -- | @(x +)@
src/Aihc/Parser/Types.hs view
@@ -8,6 +8,9 @@     mkTokStream,     mkTokStreamModule,     mkTokStreamFromTokens,+    setTokStreamLayout,+    setTokStreamPendingPragmas,+    runTokStreamParser,     ParserErrorComponent (..),     FoundToken (..),     mkFoundToken,@@ -93,7 +96,14 @@     tokStreamExtensionSet :: ExtensionSet,     -- | Whether this stream has already emitted TkEOF.     -- After EOF is emitted, 'take1_' returns Nothing.-    tokStreamEOFEmitted :: !Bool+    tokStreamEOFEmitted :: !Bool,+    -- | Memoized result of stepping this stream by one token. Lookahead and+    -- backtracking step the same position many times; sharing the successor+    -- means the layout transition for each raw token runs once.+    --+    -- Never update the other fields with record syntax: build streams with+    -- 'buildTokStream' so this field stays consistent.+    tokStreamNext :: Maybe (LexToken, TokStream)   }  -- -- Manual Eq instance — we skip tokStreamRawTokens since list position is not@@ -136,32 +146,28 @@ mkTokStream :: FilePath -> [Extension] -> Text -> TokStream mkTokStream sourceName exts input =   let (env, lexSt) = mkInitialLexerState sourceName exts input-   in normalizeTokStream-        TokStream-          { tokStreamRawTokens = scanAllTokens env lexSt,-            tokStreamLayoutState = mkInitialLayoutState False exts,-            tokStreamBuffer = [],-            tokStreamPendingPragmas = [],-            tokStreamPrevToken = Nothing,-            tokStreamExtensionSet = mkExtensionSet exts,-            tokStreamEOFEmitted = False-          }+   in normalizeTokStreamParts+        (scanAllTokens env lexSt)+        (mkInitialLayoutState False exts)+        []+        []+        Nothing+        (mkExtensionSet exts)+        False  -- | Create a TokStream for parsing full modules (with module-body layout). -- Also bootstraps LANGUAGE pragma extensions from the module header. mkTokStreamModule :: FilePath -> [Extension] -> Text -> TokStream mkTokStreamModule sourceName baseExts input =   let (env, lexSt) = mkInitialLexerState sourceName effectiveExts input-   in normalizeTokStream-        TokStream-          { tokStreamRawTokens = scanAllTokens env lexSt,-            tokStreamLayoutState = mkInitialLayoutState True effectiveExts,-            tokStreamBuffer = [],-            tokStreamPendingPragmas = [],-            tokStreamPrevToken = Nothing,-            tokStreamExtensionSet = mkExtensionSet effectiveExts,-            tokStreamEOFEmitted = False-          }+   in normalizeTokStreamParts+        (scanAllTokens env lexSt)+        (mkInitialLayoutState True effectiveExts)+        []+        []+        Nothing+        (mkExtensionSet effectiveExts)+        False   where     headerSettings = readModuleHeaderExtensions input     effectiveExts = applyImpliedExtensions (foldr applyExtensionSetting baseExts headerSettings)@@ -171,29 +177,55 @@ mkTokStreamFromTokens :: [LexToken] -> TokStream mkTokStreamFromTokens toks =   let (env, lexSt) = mkInitialLexerState "<tokens>" [] ""-   in normalizeTokStream+   in normalizeTokStreamParts+        (scanAllTokens env lexSt)+        (mkInitialLayoutState False [])+        toks+        []+        Nothing+        (mkExtensionSet [])+        False++-- | Replace the layout state and buffer of a stream. The result is a fresh+-- stream with a consistent memoized successor.+setTokStreamLayout :: LayoutState -> [LexToken] -> TokStream -> TokStream+setTokStreamLayout layoutState buffer ts =+  buildTokStream+    (tokStreamRawTokens ts)+    layoutState+    buffer+    (tokStreamPendingPragmas ts)+    (tokStreamPrevToken ts)+    (tokStreamExtensionSet ts)+    (tokStreamEOFEmitted ts)++-- | Replace the pending hidden pragmas of a stream.+setTokStreamPendingPragmas :: [Pragma] -> TokStream -> TokStream+setTokStreamPendingPragmas pendingPragmas ts =+  buildTokStream+    (tokStreamRawTokens ts)+    (tokStreamLayoutState ts)+    (tokStreamBuffer ts)+    pendingPragmas+    (tokStreamPrevToken ts)+    (tokStreamExtensionSet ts)+    (tokStreamEOFEmitted ts)++-- | Build a stream whose memoized successor is computed from its fields.+buildTokStream :: [LexToken] -> LayoutState -> [LexToken] -> [Pragma] -> Maybe LexToken -> ExtensionSet -> Bool -> TokStream+buildTokStream rawTokens layoutState buffer pendingPragmas prevToken extensionSet eofEmitted =+  let ts =         TokStream-          { tokStreamRawTokens = scanAllTokens env lexSt,-            tokStreamLayoutState = mkInitialLayoutState False [],-            tokStreamBuffer = toks,-            tokStreamPendingPragmas = [],-            tokStreamPrevToken = Nothing,-            tokStreamExtensionSet = mkExtensionSet [],-            tokStreamEOFEmitted = False+          { tokStreamRawTokens = rawTokens,+            tokStreamLayoutState = layoutState,+            tokStreamBuffer = buffer,+            tokStreamPendingPragmas = pendingPragmas,+            tokStreamPrevToken = prevToken,+            tokStreamExtensionSet = extensionSet,+            tokStreamEOFEmitted = eofEmitted,+            tokStreamNext = stepOne ts           }--normalizeTokStream :: TokStream -> TokStream-normalizeTokStream ts0-  | tokStreamEOFEmitted ts0 = ts0-  | otherwise =-      normalizeTokStreamParts-        (tokStreamRawTokens ts0)-        (tokStreamLayoutState ts0)-        (tokStreamBuffer ts0)-        (tokStreamPendingPragmas ts0)-        (tokStreamPrevToken ts0)-        (tokStreamExtensionSet ts0)-        False+   in ts  -- | Advance through layout and hidden tokens until the stream is ready for -- 'stepOne'. Keeping the stream fields separate lets a token step normalize@@ -204,15 +236,7 @@   | otherwise = go rawTokens layoutState buffer pendingPragmas   where     finish rawTokens' layoutState' buffer' pendingPragmas' =-      TokStream-        { tokStreamRawTokens = rawTokens',-          tokStreamLayoutState = layoutState',-          tokStreamBuffer = buffer',-          tokStreamPendingPragmas = pendingPragmas',-          tokStreamPrevToken = prevToken,-          tokStreamExtensionSet = extensionSet,-          tokStreamEOFEmitted = eofEmitted-        }+      buildTokStream rawTokens' layoutState' buffer' pendingPragmas' prevToken extensionSet eofEmitted      go rawTokens' layoutState' buffer' pendingPragmas' =       case buffer' of@@ -229,10 +253,9 @@             rawTok : rawRest ->               let (allToks, laySt') = layoutTransition layoutState' rawTok                in go rawRest laySt' allToks pendingPragmas'-{-# INLINE normalizeTokStreamParts #-}  -- | Step one token from the stream. This is the core primitive used by all--- Stream methods.+-- Stream methods; its result is memoized in 'tokStreamNext'. -- -- Tokens are produced in two phases: --@@ -274,8 +297,32 @@                 )         [] ->           Nothing-{-# INLINE stepOne #-} +-- | Run a token parser from the start of a stream.+--+-- The position state that Megaparsec keeps for error rendering is detached+-- from the stream, so the memoized successor chain can be collected as the+-- parser advances.+runTokStreamParser :: MP.Parsec ParserErrorComponent TokStream a -> FilePath -> TokStream -> Either ParseErrorBundle a+runTokStreamParser parser sourceName ts =+  snd (MP.runParser' parser initialState)+  where+    initialState =+      MP.State+        { MP.stateInput = ts,+          MP.stateOffset = 0,+          MP.statePosState =+            MP.PosState+              { MP.pstateInput = detachedStream,+                MP.pstateOffset = 0,+                MP.pstateSourcePos = MP.initialPos sourceName,+                MP.pstateTabWidth = MP.defaultTabWidth,+                MP.pstateLinePrefix = ""+              },+          MP.stateParseErrors = []+        }+    detachedStream = buildTokStream [] (tokStreamLayoutState ts) [] [] Nothing (tokStreamExtensionSet ts) True+ instance Stream TokStream where   type Token TokStream = LexToken   type Tokens TokStream = [LexToken]@@ -286,7 +333,7 @@   chunkLength _ = length   chunkEmpty _ = null -  take1_ = stepOne+  take1_ = tokStreamNext    takeN_ n ts     | n <= 0 = Just ([], ts)@@ -294,7 +341,7 @@     where       go 0 acc s = Just (reverse acc, s)       go k acc s =-        case stepOne s of+        case tokStreamNext s of           Nothing             | null acc -> Nothing             | otherwise -> Just (reverse acc, s)@@ -304,7 +351,7 @@     go []     where       go acc s =-        case stepOne s of+        case tokStreamNext s of           Nothing -> (reverse acc, s)           Just (tok, s')             | f tok -> go (tok : acc) s'
+ test/Test/Fixtures/equivalent/pattern/tuple-con-prefix-spacing.yaml view
@@ -0,0 +1,5 @@+extensions: []+equivalent:+  - (,) a b+  - ( , ) (a) (b)+status: pass
+ test/Test/Fixtures/golden/expr/view-pattern-arrow.yaml view
@@ -0,0 +1,6 @@+extensions: [ViewPatterns]+input: |+  (f -> x)+ast: |-+  EParen (EViewPat (EVar "f") (EVar "x"))+status: pass
+ test/Test/Fixtures/golden/module/builtin-con-promoted.yaml view
@@ -0,0 +1,9 @@+extensions: [DataKinds]+input: |+  type A = '[]+  type B = '(:)+  type C = '(,) Int Int+  type D = '(,,)+ast: |-+  Module {[DeclTypeSyn (TypeSynDecl {Prefix "A", TBuiltinCon BuiltinList Promoted}), DeclTypeSyn (TypeSynDecl {Prefix "B", TBuiltinCon BuiltinCons Promoted}), DeclTypeSyn (TypeSynDecl {Prefix "C", TApp (TApp (TBuiltinCon BuiltinTuple 2 Promoted) (TCon "Int")) (TCon "Int")}), DeclTypeSyn (TypeSynDecl {Prefix "D", TBuiltinCon BuiltinTuple 3 Promoted})]}+status: pass
+ test/Test/Fixtures/golden/module/builtin-con-unboxed-tuple-type.yaml view
@@ -0,0 +1,7 @@+extensions: [UnboxedTuples]+input: |+  type A = (# , #) Int Bool+  type B = (# , , #)+ast: |-+  Module {[DeclTypeSyn (TypeSynDecl {Prefix "A", TApp (TApp (TBuiltinCon BuiltinTuple Unboxed 2) (TCon "Int")) (TCon "Bool")}), DeclTypeSyn (TypeSynDecl {Prefix "B", TBuiltinCon BuiltinTuple Unboxed 3})]}+status: pass
test/Test/Fixtures/golden/module/data-con-infix-tuple-constructor-application.yaml view
@@ -2,5 +2,5 @@ input: |   data A b = (,) Int Int `Infix` b ast: |--  Module {[DeclData (DataDecl {Prefix "A" [TyVarBinder {"b"}], [InfixCon {BangType {TApp (TApp (TBuiltinCon TBuiltinTuple 2) (TCon "Int")) (TCon "Int")}, UnqualifiedName {"Infix"}, BangType {TVar "b"}}]})]}+  Module {[DeclData (DataDecl {Prefix "A" [TyVarBinder {"b"}], [InfixCon {BangType {TApp (TApp (TBuiltinCon BuiltinTuple 2) (TCon "Int")) (TCon "Int")}, UnqualifiedName {"Infix"}, BangType {TVar "b"}}]})]} status: pass
+ test/Test/Fixtures/golden/module/paren-reserved-operator-expr-rejected.yaml view
@@ -0,0 +1,5 @@+extensions: []+input: |+  a = (->)+status: fail+reason: GHC rejects a reserved operator as a parenthesized expression
+ test/Test/Fixtures/golden/module/promoted-arrow-rejected.yaml view
@@ -0,0 +1,5 @@+extensions: [DataKinds]+input: |+  type A = '(->)+status: fail+reason: GHC rejects '(->); the arrow has no promoted form
+ test/Test/Fixtures/golden/module/tuple-con-prefix-patterns.yaml view
@@ -0,0 +1,10 @@+extensions: []+input: |+  module TupleConPrefixPatterns where+  graph = array bounds0 [(,) v (mapMaybe key_vertex ks) | (,) v (_, _, ks) <- edges1]+  swap x = case x of (,) a b -> (b, a)+  f ((,) a b) = a+  g (,) = 1+ast: |-+  Module {ModuleHead {"TupleConPrefixPatterns"}, [DeclValue (PatternBind (PVar "graph") (EApp (EApp (EVar "array") (EVar "bounds0")) (EListComp (EApp (EApp (ETuple [Nothing, Nothing]) (EVar "v")) (EParen (EApp (EApp (EVar "mapMaybe") (EVar "key_vertex")) (EVar "ks")))) [CompGen (PBuiltinCon BuiltinTuple 2 [PVar "v", PTuple [PWildcard, PWildcard, PVar "ks"]]) (EVar "edges1")]))), DeclValue (FunctionBind "swap" [Match {MatchHeadPrefix, [PVar "x"], ECase (EVar "x") [CaseAlt (PBuiltinCon BuiltinTuple 2 [PVar "a", PVar "b"]) (ETuple [EVar "b", EVar "a"])]}]), DeclValue (FunctionBind "f" [Match {MatchHeadPrefix, [PParen (PBuiltinCon BuiltinTuple 2 [PVar "a", PVar "b"])], EVar "a"}]), DeclValue (FunctionBind "g" [Match {MatchHeadPrefix, [PBuiltinCon BuiltinTuple 2 []], EInt 1 TInteger}])]}+status: pass
+ test/Test/Fixtures/golden/module/tuple-con-typed-pattern-bind.yaml view
@@ -0,0 +1,7 @@+extensions: [MultiWayIf, PartialTypeSignatures, UnboxedTuples]+input: |+  x = if | let (,) :: _ = [] -> []+  y = if | let (#,#) :: _ = [] -> []+ast: |-+  Module {[DeclValue (PatternBind (PVar "x") (EMultiWayIf [GuardedRhs {[GuardLet [DeclValue (PatternBind (PTypeSig (PBuiltinCon BuiltinTuple 2 []) (TWildcard)) (EList []))]], EList []}])), DeclValue (PatternBind (PVar "y") (EMultiWayIf [GuardedRhs {[GuardLet [DeclValue (PatternBind (PTypeSig (PBuiltinCon BuiltinTuple Unboxed 2 []) (TWildcard)) (EList []))]], EList []}]))]}+status: pass
+ test/Test/Fixtures/golden/pattern/tuple-con-prefix-triple-paren.yaml view
@@ -0,0 +1,6 @@+extensions: []+input: |+  ((,,) a (Just b) c)+ast: |-+  PParen (PBuiltinCon BuiltinTuple 3 [PVar "a", PParen (PCon "Just" [PVar "b"]), PVar "c"])+status: pass
+ test/Test/Fixtures/golden/pattern/tuple-con-prefix-type-arg.yaml view
@@ -0,0 +1,6 @@+extensions: [TypeApplications]+input: |+  ((,) @Int a b)+ast: |-+  PParen (PBuiltinCon BuiltinTuple 2 {[TCon "Int"], [PVar "a", PVar "b"]})+status: pass
+ test/Test/Fixtures/golden/pattern/tuple-con-prefix-unapplied.yaml view
@@ -0,0 +1,6 @@+extensions: []+input: |+  (,)+ast: |-+  PBuiltinCon BuiltinTuple 2 []+status: pass
+ test/Test/Fixtures/golden/pattern/tuple-con-prefix.yaml view
@@ -0,0 +1,6 @@+extensions: []+input: |+  (,) a b+ast: |-+  PBuiltinCon BuiltinTuple 2 [PVar "a", PVar "b"]+status: pass
+ test/Test/Fixtures/golden/pattern/unboxed-tuple-con-prefix-paren.yaml view
@@ -0,0 +1,6 @@+extensions: [UnboxedTuples]+input: |+  ((#,,#) a b c)+ast: |-+  PParen (PBuiltinCon BuiltinTuple Unboxed 3 [PVar "a", PVar "b", PVar "c"])+status: pass
+ test/Test/Fixtures/golden/pattern/unboxed-tuple-con-prefix.yaml view
@@ -0,0 +1,6 @@+extensions: [UnboxedTuples]+input: |+  (#,#) a b+ast: |-+  PBuiltinCon BuiltinTuple Unboxed 2 [PVar "a", PVar "b"]+status: pass
+ test/Test/Fixtures/oracle/DataKinds/promoted-tuple-constructor.hs view
@@ -0,0 +1,7 @@+{- ORACLE_TEST pass -}+{-# LANGUAGE DataKinds #-}+module PromotedTupleConstructor where++type P = '(,) Int Bool++type T = '(,,)
+ test/Test/Fixtures/oracle/UnboxedTuples/unboxed-tuple-type-constructor.hs view
@@ -0,0 +1,7 @@+{- ORACLE_TEST pass -}+{-# LANGUAGE UnboxedTuples #-}+module UnboxedTupleTypeConstructor where++type P = (# , #) Int Bool++type T = (# , , #)
test/Test/Properties/Arb/Expr.hs view
@@ -181,7 +181,7 @@ genTypeNameQuoteType =   oneof     [ TCon <$> genConName <*> pure Unpromoted,-      pure (TBuiltinCon TBuiltinList),+      pure (TBuiltinCon BuiltinList Unpromoted),       pure (TTuple Boxed Unpromoted []),       pure (TTuple Unboxed Unpromoted [])     ]@@ -503,6 +503,9 @@           <> [EInfix simpleVarExpr op rhs | lhs /= EList [] && not (isSimpleVarExpr lhs)]           <> [EInfix lhs op rhs' | rhs' <- shrinkExpr rhs]           <> [EInfix lhs' op rhs | lhs' <- shrinkExpr lhs]+      EViewPat viewExpr rhs ->+        [EViewPat viewExpr' rhs | viewExpr' <- shrinkExpr viewExpr]+          <> [EViewPat viewExpr rhs' | rhs' <- shrinkExpr rhs]       ENegate inner -> inner : [ENegate inner' | inner' <- shrinkExpr inner]       ESectionL inner op ->         inner
test/Test/Properties/Arb/Pattern.hs view
@@ -56,13 +56,15 @@         PTuple Boxed <$> elements [[], [PVar (mkUnqualifiedName NameVarId "x"), PWildcard]],         PTuple Unboxed <$> elements [[], [PVar (mkUnqualifiedName NameVarId "x")], [PVar (mkUnqualifiedName NameVarId "x"), PWildcard]],         pure (PList []),-        PCon <$> genConName <*> pure [] <*> pure []+        PCon <$> genConName <*> pure [] <*> pure [],+        genPatternTupleCon <*> pure []       ]     recursiveGenerators =       [ PTuple Boxed <$> genTupleElemsWith,         PTuple Unboxed <$> genUnboxedTupleElemsWith,         PList <$> genListElemsWith,         genPatternConWith,+        genPatternTupleConWith,         genPatternInfixWith,         PParen <$> genPattern,         genRecordPatternWith,@@ -81,6 +83,17 @@ genPatternConWith :: Gen Pattern genPatternConWith = PCon <$> genConName <*> pure [] <*> smallList0 genPattern +-- | Generate a prefix tuple constructor such as @(,)@ or @(#,,#)@ that+-- still needs its argument patterns.+genPatternTupleCon :: Gen ([Pattern] -> Pattern)+genPatternTupleCon = do+  tupleFlavor <- elements [Boxed, Unboxed]+  arity <- chooseInt (2, 4)+  pure (PBuiltinCon (BuiltinTuple tupleFlavor arity) [])++genPatternTupleConWith :: Gen Pattern+genPatternTupleConWith = genPatternTupleCon <*> smallList0 genPattern+ genPatternTypeSigWith :: Gen Pattern genPatternTypeSigWith = PTypeSig <$> genPattern <*> genPatternType @@ -191,6 +204,9 @@         [PCon con' typeArgs args | con' <- shrinkName con]           <> [PCon con typeArgs [] | not (null args)]           <> [PCon con typeArgs args' | args' <- shrinkList shrinkPattern args]+      PBuiltinCon con typeArgs args ->+        [PBuiltinCon con typeArgs [] | not (null args)]+          <> [PBuiltinCon con typeArgs args' | args' <- shrinkList shrinkPattern args]       PInfix lhs op rhs ->         [lhs, rhs]           <> [PInfix lhs' op rhs | lhs' <- shrinkPattern lhs]
test/Test/Properties/Arb/Type.hs view
@@ -41,7 +41,7 @@         [ TVar <$> genTypeVarName,           (`TCon` Unpromoted) <$> genConName,           (`TCon` Promoted) <$> genConName,-          TBuiltinCon <$> genTypeBuiltinCon,+          genBuiltinConType,           TTypeLit <$> genTypeLiteral,           pure (TStar "*"),           pure TWildcard,@@ -56,7 +56,7 @@         [ TVar <$> genTypeVarName,           (`TCon` Unpromoted) <$> genConName,           (`TCon` Promoted) <$> genConName,-          TBuiltinCon <$> genTypeBuiltinCon,+          genBuiltinConType,           TTypeLit <$> genTypeLiteral,           pure (TStar "*"),           pure TWildcard,@@ -288,15 +288,21 @@         pure (TypeLitChar c (T.pack (show c)))     ] -genTypeBuiltinCon :: Gen TypeBuiltinCon-genTypeBuiltinCon =-  elements-    [ TBuiltinTuple 2,-      TBuiltinTuple 3,-      TBuiltinArrow,-      TBuiltinList,-      TBuiltinCons-    ]+-- | Generate a built-in type constructor with a promotion flag.+-- @'(->)@ has no valid syntax, so the arrow stays unpromoted.+genBuiltinConType :: Gen Type+genBuiltinConType = do+  con <-+    elements+      [ BuiltinTuple Boxed 2,+        BuiltinTuple Boxed 3,+        BuiltinTuple Unboxed 2,+        BuiltinArrow,+        BuiltinList,+        BuiltinCons+      ]+  promotion <- if con == BuiltinArrow then pure Unpromoted else elements [Unpromoted, Promoted]+  pure (TBuiltinCon con promotion)  genSymbolText :: Gen Text genSymbolText = do