diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,16 @@
 
 ## [Unreleased]
 
+## [2.0.0.0] - 2026-09-03
+
+### Changed
+
+- Added dedicated `EImplicitParam` and `DeclImplicitParam` AST constructors
+  for `?x` expressions and `?x = e` bindings under `ImplicitParams`. These
+  forms previously reused `EVar` and `PatternBind`/`PVar`, which made an
+  implicit parameter indistinguishable from an ordinary variable downstream.
+  `TImplicitParam` (the type-level form) is unchanged.
+
 ## [1.0.0.6] - 2026-09-02
 
 ### Changed
diff --git a/aihc-parser.cabal b/aihc-parser.cabal
--- a/aihc-parser.cabal
+++ b/aihc-parser.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.8
 name: aihc-parser
-version: 1.0.0.6
+version: 2.0.0.0
 build-type: Simple
 license: Unlicense
 license-file: LICENSE
diff --git a/src/Aihc/Parser/Internal/CheckPattern.hs b/src/Aihc/Parser/Internal/CheckPattern.hs
--- a/src/Aihc/Parser/Internal/CheckPattern.hs
+++ b/src/Aihc/Parser/Internal/CheckPattern.hs
@@ -38,6 +38,7 @@
     | isConLikeName name -> Right (PCon name [] [])
     | isJust (nameQualifier name) -> Left "unexpected qualified name in pattern"
     | otherwise -> Right (PVar (nameToUnqualified name))
+  EImplicitParam {} -> Left "unexpected implicit parameter in pattern"
   ETypeSyntax form ty -> Right (PTypeSyntax form ty)
   -- Parenthesized expression
   -- When the inner expression is a view-pattern arrow (@expr -> expr@),
diff --git a/src/Aihc/Parser/Internal/Expr.hs b/src/Aihc/Parser/Internal/Expr.hs
--- a/src/Aihc/Parser/Internal/Expr.hs
+++ b/src/Aihc/Parser/Internal/Expr.hs
@@ -1306,13 +1306,7 @@
   expectedTok TkReservedEquals
   rhsExpr <- exprParser
   whereDecls <- MP.optional whereClauseParser
-  pure $
-    DeclValue
-      ( PatternBind
-          NoMultiplicityTag
-          (PVar (mkUnqualifiedName NameVarId name))
-          (UnguardedRhs [] rhsExpr whereDecls)
-      )
+  pure $ DeclImplicitParam name rhsExpr whereDecls
 
 varExprParser :: TokParser Expr
 varExprParser = do
@@ -1327,7 +1321,7 @@
         Just $
           EAnn
             (mkAnnotation (lexTokenSpan tok))
-            (EVar (qualifyName Nothing (mkUnqualifiedNameAt tok NameVarId name)))
+            (EImplicitParam name)
       _ -> Nothing
 
 wildcardExprParser :: TokParser Expr
diff --git a/src/Aihc/Parser/Parens.hs b/src/Aihc/Parser/Parens.hs
--- a/src/Aihc/Parser/Parens.hs
+++ b/src/Aihc/Parser/Parens.hs
@@ -606,6 +606,8 @@
   case decl of
     DeclAnn ann sub -> DeclAnn ann (addDeclParens sub)
     DeclValue vdecl -> DeclValue (addValueDeclParens vdecl)
+    DeclImplicitParam name body whereDecls ->
+      DeclImplicitParam name (addExprParens body) (fmap (map addDeclParens) whereDecls)
     DeclTypeSig names ty -> DeclTypeSig names (addSignatureTypeParens ty)
     DeclPatSyn ps -> DeclPatSyn (addPatSynDeclParens ps)
     DeclPatSynSig names ty -> DeclPatSynSig names (addSignatureTypeParens ty)
@@ -1078,6 +1080,7 @@
        in wrapExpr (prec > 2) (ETypeApp fn' (addTypeIn CtxTypeAppVisibleArg ty))
     ETypeSyntax form ty -> wrapExpr (prec > 2) (ETypeSyntax form (addSignatureTypeParens ty))
     EVar {} -> expr
+    EImplicitParam {} -> expr
     EInt {} -> expr
     EFloat {} -> expr
     EChar {} -> expr
diff --git a/src/Aihc/Parser/Pretty.hs b/src/Aihc/Parser/Pretty.hs
--- a/src/Aihc/Parser/Pretty.hs
+++ b/src/Aihc/Parser/Pretty.hs
@@ -247,6 +247,8 @@
   case decl of
     DeclAnn _ sub -> prettyDeclLines sub
     DeclValue valueDecl -> prettyValueDeclLines valueDecl
+    DeclImplicitParam name expr whereDecls ->
+      [pretty name <+> "=" <+> prettyExpr expr <> prettyIndentedWhereClause whereDecls]
     DeclTypeSig names ty -> [hsep [hsep (punctuate comma (map prettyBinderName names)), "::", prettyType ty]]
     DeclPatSyn patSynDecl -> [prettyPatSynDecl patSynDecl]
     DeclPatSynSig names ty -> [hsep ["pattern", hsep (punctuate comma (map prettyConstructorUName names)), "::", prettyType ty]]
@@ -1150,6 +1152,7 @@
     ETypeApp fn ty ->
       nest 2 (prettyExpr fn) <> nest 1 (hardline <> " " <> prettyTypeAppArg ty)
     EVar name -> prettyName name
+    EImplicitParam name -> pretty name
     ETypeSyntax TypeSyntaxExplicitNamespace ty -> "type" <+> prettyType ty
     ETypeSyntax TypeSyntaxInTerm ty -> prettyType ty
     EInt _ _ repr -> pretty repr
diff --git a/src/Aihc/Parser/Shorthand.hs b/src/Aihc/Parser/Shorthand.hs
--- a/src/Aihc/Parser/Shorthand.hs
+++ b/src/Aihc/Parser/Shorthand.hs
@@ -210,6 +210,11 @@
   case decl of
     DeclAnn _ sub -> docDecl sub
     DeclValue vdecl -> "DeclValue" <+> parens (docValueDecl vdecl)
+    DeclImplicitParam name expr whereDecls ->
+      "DeclImplicitParam"
+        <+> docText name
+        <+> parens (docExpr expr)
+        <+> maybe "Nothing" (\decls -> "Just" <+> brackets (hsep (punctuate comma (map docDecl decls)))) whereDecls
     DeclTypeSig names ty -> "DeclTypeSig" <+> brackets (hsep (punctuate comma (map docUnqualifiedNameText names))) <+> parens (docType ty)
     DeclPatSyn ps -> "DeclPatSyn" <+> parens (docPatSynDecl ps)
     DeclPatSynSig names ty -> "DeclPatSynSig" <+> brackets (hsep (punctuate comma (map docUnqualifiedName names))) <+> parens (docType ty)
@@ -828,6 +833,7 @@
 docExpr expr =
   case expr of
     EVar name -> "EVar" <+> docName name
+    EImplicitParam name -> "EImplicitParam" <+> docText name
     ETypeSyntax form ty -> "ETypeSyntax" <+> docTypeSyntaxForm form <+> parens (docType ty)
     EInt n nt _ -> "EInt" <+> pretty n <+> docNumericType nt
     EFloat n ft _ -> "EFloat" <+> pretty (show n) <+> docFloatType ft
diff --git a/src/Aihc/Parser/Syntax.hs b/src/Aihc/Parser/Syntax.hs
--- a/src/Aihc/Parser/Syntax.hs
+++ b/src/Aihc/Parser/Syntax.hs
@@ -1028,6 +1028,8 @@
     DeclAnn Annotation Decl
   | -- | @f x = x@ or @x = 1@
     DeclValue ValueDecl
+  | -- | @?x = e@ in a @let@ or @where@ group
+    DeclImplicitParam Text Expr (Maybe [Decl])
   | -- | @f, g :: Int -> Int@
     DeclTypeSig [BinderName] Type
   | -- | @pattern P x = Just x@
@@ -1986,6 +1988,8 @@
     EAnn Annotation Expr
   | -- | @x@ or @Data.List.map@
     EVar Name
+  | -- | @?x@
+    EImplicitParam Text
   | -- | @type T@ in a term position.
     ETypeSyntax TypeSyntaxForm Type
   | -- | @1@, @1#@, @1#Word8@
diff --git a/test/Test/Properties/Arb/Decl.hs b/test/Test/Properties/Arb/Decl.hs
--- a/test/Test/Properties/Arb/Decl.hs
+++ b/test/Test/Properties/Arb/Decl.hs
@@ -18,13 +18,14 @@
 import Data.Maybe (fromMaybe, isJust)
 import Data.Text (Text)
 import Data.Text qualified as T
-import {-# SOURCE #-} Test.Properties.Arb.Expr (genRhs, shrinkExpr, shrinkGuardQualifier)
+import {-# SOURCE #-} Test.Properties.Arb.Expr (genExpr, genRhs, shrinkExpr, shrinkGuardQualifier)
 import Test.Properties.Arb.Identifiers
   ( genConId,
     genConName,
     genConSym,
     genConUnqualifiedName,
     genVarId,
+    genVarIdNoHash,
     genVarName,
     genVarSym,
     genVarUnqualifiedName,
@@ -119,8 +120,29 @@
 genPatternValueDecl =
   PatternBind NoMultiplicityTag <$> genPattern <*> genRhs
 
+-- | GHC's grammar has no @where@ clause on an implicit-parameter binding
+-- (@dbind : ipvar '=' exp@ in GHC's @Parser.y@); the parser only accepts one
+-- for backwards compatibility with the old encoding (see
+-- 'Aihc.Parser.Syntax.DeclImplicitParam'). Never generate one here so that
+-- generated sources stay accepted by GHC itself.
+genDeclImplicitParam :: Gen Decl
+genDeclImplicitParam = do
+  name <- ("?" <>) <$> genVarIdNoHash
+  expr <- genExpr
+  pure (DeclImplicitParam name expr Nothing)
+
+-- | A @where@ clause is either all ordinary value bindings or all implicit
+-- parameter bindings: GHC's grammar does not allow mixing the two forms in
+-- the same binding group (verifying that a mixed group is rejected is left
+-- to a downstream package, see the issue this constructor was added for).
 genWhereDecls :: Gen (Maybe [Decl])
-genWhereDecls = optional $ scale (`div` 2) $ listOf (DeclValue <$> genDeclValue)
+genWhereDecls =
+  optional $
+    scale (`div` 2) $
+      oneof
+        [ listOf (DeclValue <$> genDeclValue),
+          listOf1 genDeclImplicitParam
+        ]
 
 genDeclTypeSig :: Gen Decl
 genDeclTypeSig = DeclTypeSig <$> smallList1 genVarUnqualifiedName <*> genType
@@ -1166,6 +1188,9 @@
   case decl of
     DeclAnn _ inner -> inner : shrinkDecl inner
     DeclValue vd -> map DeclValue (shrinkValueDecl vd)
+    DeclImplicitParam name expr mWhere ->
+      [DeclImplicitParam name expr' mWhere | expr' <- shrinkExpr expr]
+        <> [DeclImplicitParam name expr (Just ds') | Just ds <- [mWhere], ds' <- shrinkWhereDecls ds]
     DeclTypeSig names ty ->
       [DeclTypeSig names' ty | names' <- shrinkList shrinkBinderName names, not (null names')]
         <> [DeclTypeSig names ty' | ty' <- shrinkType ty]
diff --git a/test/Test/Properties/Arb/Expr.hs b/test/Test/Properties/Arb/Expr.hs
--- a/test/Test/Properties/Arb/Expr.hs
+++ b/test/Test/Properties/Arb/Expr.hs
@@ -474,6 +474,7 @@
   [EList [] | expr /= EList []]
     ++ case expr of
       EVar name -> [EVar name' | name' <- shrinkName name]
+      EImplicitParam _ -> []
       ETypeSyntax form ty -> [ETypeSyntax form ty' | ty' <- shrinkType ty]
       EInt value _ _ -> simpleVarExpr : [mkIntExpr shrunk | shrunk <- shrinkIntegral value]
       EFloat value _ _ -> simpleVarExpr : [mkFloatExpr shrunk | shrunk <- shrinkFloat value]
