diff options
author | Simon Peyton Jones <simonpj@microsoft.com> | 2021-05-04 08:45:08 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-05-07 09:43:57 -0400 |
commit | 8e0f48bdd6e83279939d8fdd2ec1e5707725030d (patch) | |
tree | bc65d57cf1c9b05acc5f54a9627ecfce465e6e0c /compiler/GHC/Hs/Expr.hs | |
parent | a664a2ad6432ad19799cf5670311f5d1aaac0559 (diff) | |
download | haskell-8e0f48bdd6e83279939d8fdd2ec1e5707725030d.tar.gz |
Allow visible type application for levity-poly data cons
This patch was driven by #18481, to allow visible type application
for levity-polymorphic newtypes. As so often, it started simple
but grew:
* Significant refactor: I removed HsConLikeOut from the
client-independent Language.Haskell.Syntax.Expr, and put it where it
belongs, as a new constructor `ConLikeTc` in the GHC-specific extension
data type for expressions, `GHC.Hs.Expr.XXExprGhcTc`.
That changed touched a lot of files in a very superficial way.
* Note [Typechecking data constructors] explains the main payload.
The eta-expansion part is no longer done by the typechecker, but
instead deferred to the desugarer, via `ConLikeTc`
* A little side benefit is that I was able to restore VTA for
data types with a "stupid theta": #19775. Not very important,
but the code in GHC.Tc.Gen.Head.tcInferDataCon is is much, much
more elegant now.
* I had to refactor the levity-polymorphism checking code in
GHC.HsToCore.Expr, see
Note [Checking for levity-polymorphic functions]
Note [Checking levity-polymorphic data constructors]
Diffstat (limited to 'compiler/GHC/Hs/Expr.hs')
-rw-r--r-- | compiler/GHC/Hs/Expr.hs | 202 |
1 files changed, 124 insertions, 78 deletions
diff --git a/compiler/GHC/Hs/Expr.hs b/compiler/GHC/Hs/Expr.hs index fb523bb74a..f812c66540 100644 --- a/compiler/GHC/Hs/Expr.hs +++ b/compiler/GHC/Hs/Expr.hs @@ -52,6 +52,7 @@ import GHC.Types.Basic import GHC.Types.Fixity import GHC.Types.SourceText import GHC.Types.SrcLoc +import GHC.Types.Var( InvisTVBinder ) import GHC.Core.ConLike import GHC.Unit.Module (ModuleName) import GHC.Utils.Misc @@ -218,7 +219,6 @@ data EpAnnUnboundVar = EpAnnUnboundVar } deriving Data type instance XVar (GhcPass _) = NoExtField -type instance XConLikeOut (GhcPass _) = NoExtField type instance XRecFld (GhcPass _) = NoExtField type instance XLam (GhcPass _) = NoExtField @@ -240,7 +240,6 @@ type instance XUnboundVar GhcTc = HoleExprRef -- Much, much easier just to define HoleExprRef with a Data instance and -- store the whole structure. -type instance XConLikeOut (GhcPass _) = NoExtField type instance XRecFld (GhcPass _) = NoExtField type instance XIPVar (GhcPass _) = EpAnnCO type instance XOverLitE (GhcPass _) = EpAnnCO @@ -361,21 +360,9 @@ type instance XBinTick (GhcPass _) = NoExtField type instance XPragE (GhcPass _) = NoExtField -type instance XXExpr GhcPs = NoExtCon - --- See Note [Rebindable syntax and HsExpansion] below -type instance XXExpr GhcRn = HsExpansion (HsExpr GhcRn) - (HsExpr GhcRn) -type instance XXExpr GhcTc = XXExprGhcTc - - type instance Anno [LocatedA ((StmtLR (GhcPass pl) (GhcPass pr) (LocatedA (body (GhcPass pr)))))] = SrcSpanAnnL type instance Anno (StmtLR GhcRn GhcRn (LocatedA (body GhcRn))) = SrcSpanAnnA -data XXExprGhcTc - = WrapExpr {-# UNPACK #-} !(HsWrap HsExpr) - | ExpansionExpr {-# UNPACK #-} !(HsExpansion (HsExpr GhcRn) (HsExpr GhcTc)) - data AnnExplicitSum = AnnExplicitSum { aesOpen :: EpaLocation, @@ -421,6 +408,40 @@ tupArgPresent :: HsTupArg (GhcPass p) -> Bool tupArgPresent (Present {}) = True tupArgPresent (Missing {}) = False + +{- ********************************************************************* +* * + XXExpr: the extension constructor of HsExpr +* * +********************************************************************* -} + +type instance XXExpr GhcPs = NoExtCon +type instance XXExpr GhcRn = HsExpansion (HsExpr GhcRn) (HsExpr GhcRn) +type instance XXExpr GhcTc = XXExprGhcTc +-- HsExpansion: see Note [Rebindable syntax and HsExpansion] below + + +data XXExprGhcTc + = WrapExpr -- Type and evidence application and abstractions + {-# UNPACK #-} !(HsWrap HsExpr) + + | ExpansionExpr -- See Note [Rebindable syntax and HsExpansion] below + {-# UNPACK #-} !(HsExpansion (HsExpr GhcRn) (HsExpr GhcTc)) + + | ConLikeTc -- Result of typechecking a data-con + -- See Note [Typechecking data constructors] in + -- GHC.Tc.Gen.Head + -- The two arguments describe how to eta-expand + -- the data constructor when desugaring + ConLike [InvisTVBinder] [Scaled TcType] + + +{- ********************************************************************* +* * + Pretty-printing expressions +* * +********************************************************************* -} + instance (OutputableBndrId p) => Outputable (HsExpr (GhcPass p)) where ppr expr = pprExpr expr @@ -457,7 +478,6 @@ ppr_expr :: forall p. (OutputableBndrId p) => HsExpr (GhcPass p) -> SDoc ppr_expr (HsVar _ (L _ v)) = pprPrefixOcc v ppr_expr (HsUnboundVar _ uv) = pprPrefixOcc uv -ppr_expr (HsConLikeOut _ c) = pprPrefixOcc c ppr_expr (HsRecFld _ f) = pprPrefixOcc f ppr_expr (HsIPVar _ v) = ppr v ppr_expr (HsOverLabel _ l) = char '#' <> ppr l @@ -638,27 +658,41 @@ ppr_expr (XExpr x) = case ghcPass @p of GhcPs -> ppr x #endif GhcRn -> ppr x - GhcTc -> case x of - WrapExpr (HsWrap co_fn e) -> pprHsWrapper co_fn - (\parens -> if parens then pprExpr e else pprExpr e) - ExpansionExpr e -> ppr e -- e is an HsExpansion, we print the original - -- expression (LHsExpr GhcPs), not the - -- desugared one (LHsExpr GhcT). + GhcTc -> ppr x + +instance Outputable XXExprGhcTc where + ppr (WrapExpr (HsWrap co_fn e)) + = pprHsWrapper co_fn (\_parens -> pprExpr e) + + ppr (ExpansionExpr e) + = ppr e -- e is an HsExpansion, we print the original + -- expression (LHsExpr GhcPs), not the + -- desugared one (LHsExpr GhcTc). + + ppr (ConLikeTc con _ _) = pprPrefixOcc con + -- Used in error messages generated by + -- the pattern match overlap checker ppr_infix_expr :: forall p. (OutputableBndrId p) => HsExpr (GhcPass p) -> Maybe SDoc ppr_infix_expr (HsVar _ (L _ v)) = Just (pprInfixOcc v) -ppr_infix_expr (HsConLikeOut _ c) = Just (pprInfixOcc (conLikeName c)) ppr_infix_expr (HsRecFld _ f) = Just (pprInfixOcc f) ppr_infix_expr (HsUnboundVar _ occ) = Just (pprInfixOcc occ) -ppr_infix_expr (XExpr x) = case (ghcPass @p, x) of +ppr_infix_expr (XExpr x) = case ghcPass @p of #if __GLASGOW_HASKELL__ < 901 - (GhcPs, _) -> Nothing + GhcPs -> Nothing #endif - (GhcRn, HsExpanded a _) -> ppr_infix_expr a - (GhcTc, WrapExpr (HsWrap _ e)) -> ppr_infix_expr e - (GhcTc, ExpansionExpr (HsExpanded a _)) -> ppr_infix_expr a + GhcRn -> ppr_infix_expr_rn x + GhcTc -> ppr_infix_expr_tc x ppr_infix_expr _ = Nothing +ppr_infix_expr_rn :: HsExpansion (HsExpr GhcRn) (HsExpr GhcRn) -> Maybe SDoc +ppr_infix_expr_rn (HsExpanded a _) = ppr_infix_expr a + +ppr_infix_expr_tc :: XXExprGhcTc -> Maybe SDoc +ppr_infix_expr_tc (WrapExpr (HsWrap _ e)) = ppr_infix_expr e +ppr_infix_expr_tc (ExpansionExpr (HsExpanded a _)) = ppr_infix_expr a +ppr_infix_expr_tc (ConLikeTc {}) = Nothing + ppr_apps :: (OutputableBndrId p) => HsExpr (GhcPass p) -> [Either (LHsExpr (GhcPass p)) (LHsWcType (NoGhcTc (GhcPass p)))] @@ -698,67 +732,70 @@ pprParendExpr p expr -- | @'hsExprNeedsParens' p e@ returns 'True' if the expression @e@ needs -- parentheses under precedence @p@. hsExprNeedsParens :: forall p. IsPass p => PprPrec -> HsExpr (GhcPass p) -> Bool -hsExprNeedsParens p = go +hsExprNeedsParens prec = go where + go :: HsExpr (GhcPass p) -> Bool go (HsVar{}) = False go (HsUnboundVar{}) = False - go (HsConLikeOut{}) = False go (HsIPVar{}) = False go (HsOverLabel{}) = False - go (HsLit _ l) = hsLitNeedsParens p l - go (HsOverLit _ ol) = hsOverLitNeedsParens p ol + go (HsLit _ l) = hsLitNeedsParens prec l + go (HsOverLit _ ol) = hsOverLitNeedsParens prec ol go (HsPar{}) = False - go (HsApp{}) = p >= appPrec - go (HsAppType {}) = p >= appPrec - go (OpApp{}) = p >= opPrec - go (NegApp{}) = p > topPrec + go (HsApp{}) = prec >= appPrec + go (HsAppType {}) = prec >= appPrec + go (OpApp{}) = prec >= opPrec + go (NegApp{}) = prec > topPrec go (SectionL{}) = True go (SectionR{}) = True -- Special-case unary boxed tuple applications so that they are -- parenthesized as `Identity (Solo x)`, not `Identity Solo x` (#18612) -- See Note [One-tuples] in GHC.Builtin.Types go (ExplicitTuple _ [Present{}] Boxed) - = p >= appPrec + = prec >= appPrec go (ExplicitTuple{}) = False go (ExplicitSum{}) = False - go (HsLam{}) = p > topPrec - go (HsLamCase{}) = p > topPrec - go (HsCase{}) = p > topPrec - go (HsIf{}) = p > topPrec - go (HsMultiIf{}) = p > topPrec - go (HsLet{}) = p > topPrec + go (HsLam{}) = prec > topPrec + go (HsLamCase{}) = prec > topPrec + go (HsCase{}) = prec > topPrec + go (HsIf{}) = prec > topPrec + go (HsMultiIf{}) = prec > topPrec + go (HsLet{}) = prec > topPrec go (HsDo _ sc _) | isComprehensionContext sc = False - | otherwise = p > topPrec + | otherwise = prec > topPrec go (ExplicitList{}) = False go (RecordUpd{}) = False - go (ExprWithTySig{}) = p >= sigPrec + go (ExprWithTySig{}) = prec >= sigPrec go (ArithSeq{}) = False - go (HsPragE{}) = p >= appPrec + go (HsPragE{}) = prec >= appPrec go (HsSpliceE{}) = False go (HsBracket{}) = False go (HsRnBracketOut{}) = False go (HsTcBracketOut{}) = False - go (HsProc{}) = p > topPrec - go (HsStatic{}) = p >= appPrec + go (HsProc{}) = prec > topPrec + go (HsStatic{}) = prec >= appPrec go (HsTick _ _ (L _ e)) = go e go (HsBinTick _ _ _ (L _ e)) = go e go (RecordCon{}) = False go (HsRecFld{}) = False go (HsProjection{}) = True go (HsGetField{}) = False - go (XExpr x) - | GhcTc <- ghcPass @p - = case x of - WrapExpr (HsWrap _ e) -> go e - ExpansionExpr (HsExpanded a _) -> hsExprNeedsParens p a - | GhcRn <- ghcPass @p - = case x of HsExpanded a _ -> hsExprNeedsParens p a + go (XExpr x) = case ghcPass @p of + GhcTc -> go_x_tc x + GhcRn -> go_x_rn x #if __GLASGOW_HASKELL__ <= 900 - | otherwise - = True + GhcPs -> True #endif + go_x_tc :: XXExprGhcTc -> Bool + go_x_tc (WrapExpr (HsWrap _ e)) = hsExprNeedsParens prec e + go_x_tc (ExpansionExpr (HsExpanded a _)) = hsExprNeedsParens prec a + go_x_tc (ConLikeTc {}) = False + + go_x_rn :: HsExpansion (HsExpr GhcRn) (HsExpr GhcRn) -> Bool + go_x_rn (HsExpanded a _) = hsExprNeedsParens prec a + -- | @'parenthesizeHsExpr' p e@ checks if @'hsExprNeedsParens' p e@ is true, -- and if so, surrounds @e@ with an 'HsPar'. Otherwise, it simply returns @e@. @@ -778,7 +815,6 @@ stripParensHsExpr e = e isAtomicHsExpr :: forall p. IsPass p => HsExpr (GhcPass p) -> Bool -- True of a single token isAtomicHsExpr (HsVar {}) = True -isAtomicHsExpr (HsConLikeOut {}) = True isAtomicHsExpr (HsLit {}) = True isAtomicHsExpr (HsOverLit {}) = True isAtomicHsExpr (HsIPVar {}) = True @@ -786,12 +822,16 @@ isAtomicHsExpr (HsOverLabel {}) = True isAtomicHsExpr (HsUnboundVar {}) = True isAtomicHsExpr (HsRecFld{}) = True isAtomicHsExpr (XExpr x) - | GhcTc <- ghcPass @p = case x of - WrapExpr (HsWrap _ e) -> isAtomicHsExpr e - ExpansionExpr (HsExpanded a _) -> isAtomicHsExpr a - | GhcRn <- ghcPass @p = case x of - HsExpanded a _ -> isAtomicHsExpr a -isAtomicHsExpr _ = False + | GhcTc <- ghcPass @p = go_x_tc x + | GhcRn <- ghcPass @p = go_x_rn x + where + go_x_tc (WrapExpr (HsWrap _ e)) = isAtomicHsExpr e + go_x_tc (ExpansionExpr (HsExpanded a _)) = isAtomicHsExpr a + go_x_tc (ConLikeTc {}) = True + + go_x_rn (HsExpanded a _) = isAtomicHsExpr a + +isAtomicHsExpr _ = False instance Outputable (HsPragE (GhcPass p)) where ppr (HsPragSCC _ st (StringLiteral stl lbl _)) = @@ -1108,21 +1148,27 @@ ppr_cmd (HsCmdArrApp _ arrow arg HsHigherOrderApp True) ppr_cmd (HsCmdArrApp _ arrow arg HsHigherOrderApp False) = hsep [ppr_lexpr arg, arrowtt, ppr_lexpr arrow] -ppr_cmd (HsCmdArrForm _ (L _ (HsVar _ (L _ v))) _ (Just _) [arg1, arg2]) - = hang (pprCmdArg (unLoc arg1)) 4 (sep [ pprInfixOcc v - , pprCmdArg (unLoc arg2)]) -ppr_cmd (HsCmdArrForm _ (L _ (HsVar _ (L _ v))) Infix _ [arg1, arg2]) - = hang (pprCmdArg (unLoc arg1)) 4 (sep [ pprInfixOcc v - , pprCmdArg (unLoc arg2)]) -ppr_cmd (HsCmdArrForm _ (L _ (HsConLikeOut _ c)) _ (Just _) [arg1, arg2]) - = hang (pprCmdArg (unLoc arg1)) 4 (sep [ pprInfixOcc (conLikeName c) - , pprCmdArg (unLoc arg2)]) -ppr_cmd (HsCmdArrForm _ (L _ (HsConLikeOut _ c)) Infix _ [arg1, arg2]) - = hang (pprCmdArg (unLoc arg1)) 4 (sep [ pprInfixOcc (conLikeName c) - , pprCmdArg (unLoc arg2)]) -ppr_cmd (HsCmdArrForm _ op _ _ args) - = hang (text "(|" <+> ppr_lexpr op) - 4 (sep (map (pprCmdArg.unLoc) args) <+> text "|)") +ppr_cmd (HsCmdArrForm _ (L _ op) ps_fix rn_fix args) + | HsVar _ (L _ v) <- op + = ppr_cmd_infix v + | GhcTc <- ghcPass @p + , XExpr (ConLikeTc c _ _) <- op + = ppr_cmd_infix (conLikeName c) + | otherwise + = fall_through + where + fall_through = hang (text "(|" <+> ppr_expr op) + 4 (sep (map (pprCmdArg.unLoc) args) <+> text "|)") + + ppr_cmd_infix :: OutputableBndr v => v -> SDoc + ppr_cmd_infix v + | [arg1, arg2] <- args + , isJust rn_fix || ps_fix == Infix + = hang (pprCmdArg (unLoc arg1)) + 4 (sep [ pprInfixOcc v, pprCmdArg (unLoc arg2)]) + | otherwise + = fall_through + ppr_cmd (XCmd x) = case ghcPass @p of #if __GLASGOW_HASKELL__ < 811 GhcPs -> ppr x |