module GHC.HsToCore.Pmc.Desugar (
desugarPatBind, desugarGRHSs, desugarMatches, desugarEmptyCase
) where
#include "HsVersions.h"
import GHC.Prelude
import GHC.HsToCore.Pmc.Types
import GHC.HsToCore.Pmc.Utils
import GHC.Core (Expr(Var,App))
import GHC.Data.FastString (unpackFS, lengthFS)
import GHC.Data.Bag (bagToList)
import GHC.Driver.Session
import GHC.Hs
import GHC.Tc.Utils.Zonk (shortCutLit)
import GHC.Types.Id
import GHC.Core.ConLike
import GHC.Types.Name
import GHC.Builtin.Types
import GHC.Builtin.Names (rationalTyConName)
import GHC.Types.SrcLoc
import GHC.Utils.Outputable
import GHC.Utils.Panic
import GHC.Utils.Misc
import GHC.Core.DataCon
import GHC.Types.Var (EvVar)
import GHC.Core.Coercion
import GHC.Tc.Types.Evidence (HsWrapper(..), isIdHsWrapper)
import GHC.HsToCore.Expr (dsExpr, dsLExpr, dsSyntaxExpr)
import GHC.HsToCore.Binds (dsHsWrapper)
import GHC.HsToCore.Utils (isTrueLHsExpr, selectMatchVar)
import GHC.HsToCore.Match.Literal (dsLit, dsOverLit)
import GHC.HsToCore.Monad
import GHC.Core.TyCo.Rep
import GHC.Core.Type
import GHC.Data.Maybe
import qualified GHC.LanguageExtensions as LangExt
import GHC.Utils.Monad (concatMapM)
import GHC.Types.SourceText (FractionalLit(..))
import Control.Monad (zipWithM)
import Data.List (elemIndex)
import Data.List.NonEmpty ( NonEmpty(..) )
import qualified Data.List.NonEmpty as NE
mkPmLetVar :: Id -> Id -> [PmGrd]
mkPmLetVar x y | x == y = []
mkPmLetVar x y = [PmLet x (Var y)]
vanillaConGrd :: Id -> DataCon -> [Id] -> PmGrd
vanillaConGrd scrut con arg_ids =
PmCon { pm_id = scrut, pm_con_con = PmAltConLike (RealDataCon con)
, pm_con_tvs = [], pm_con_dicts = [], pm_con_args = arg_ids }
mkListGrds :: Id -> [(Id, [PmGrd])] -> DsM [PmGrd]
mkListGrds a [] = pure [vanillaConGrd a nilDataCon []]
mkListGrds a ((x, head_grds):xs) = do
b <- mkPmId (idType a)
tail_grds <- mkListGrds b xs
pure $ vanillaConGrd a consDataCon [x, b] : head_grds ++ tail_grds
mkPmLitGrds :: Id -> PmLit -> DsM [PmGrd]
mkPmLitGrds x (PmLit _ (PmLitString s)) = do
vars <- traverse mkPmId (take (lengthFS s) (repeat charTy))
let mk_char_lit y c = mkPmLitGrds y (PmLit charTy (PmLitChar c))
char_grdss <- zipWithM mk_char_lit vars (unpackFS s)
mkListGrds x (zip vars char_grdss)
mkPmLitGrds x lit = do
let grd = PmCon { pm_id = x
, pm_con_con = PmAltLit lit
, pm_con_tvs = []
, pm_con_dicts = []
, pm_con_args = [] }
pure [grd]
desugarPat :: Id -> Pat GhcTc -> DsM [PmGrd]
desugarPat x pat = case pat of
WildPat _ty -> pure []
VarPat _ y -> pure (mkPmLetVar (unLoc y) x)
ParPat _ p -> desugarLPat x p
LazyPat _ _ -> pure []
BangPat _ p@(L l p') ->
(PmBang x pm_loc :) <$> desugarLPat x p
where pm_loc = Just (SrcInfo (L (locA l) (ppr p')))
AsPat _ (L _ y) p -> (mkPmLetVar y x ++) <$> desugarLPat y p
SigPat _ p _ty -> desugarLPat x p
XPat (CoPat wrapper p _ty)
| isIdHsWrapper wrapper -> desugarPat x p
| WpCast co <- wrapper, isReflexiveCo co -> desugarPat x p
| otherwise -> do
(y, grds) <- desugarPatV p
wrap_rhs_y <- dsHsWrapper wrapper
pure (PmLet y (wrap_rhs_y (Var x)) : grds)
NPlusKPat _pat_ty (L _ n) k1 k2 ge minus -> do
b <- mkPmId boolTy
let grd_b = vanillaConGrd b trueDataCon []
[ke1, ke2] <- traverse dsOverLit [unLoc k1, k2]
rhs_b <- dsSyntaxExpr ge [Var x, ke1]
rhs_n <- dsSyntaxExpr minus [Var x, ke2]
pure [PmLet b rhs_b, grd_b, PmLet n rhs_n]
ViewPat _arg_ty lexpr pat -> do
(y, grds) <- desugarLPatV pat
fun <- dsLExpr lexpr
pure $ PmLet y (App fun (Var x)) : grds
ListPat (ListPatTc _elem_ty Nothing) ps ->
desugarListPat x ps
ListPat (ListPatTc elem_ty (Just (pat_ty, to_list))) pats -> do
dflags <- getDynFlags
case splitListTyConApp_maybe pat_ty of
Just _e_ty
| not (xopt LangExt.RebindableSyntax dflags)
-> desugarListPat x pats
_ -> do
y <- mkPmId (mkListTy elem_ty)
grds <- desugarListPat y pats
rhs_y <- dsSyntaxExpr to_list [Var x]
pure $ PmLet y rhs_y : grds
ConPat { pat_con = L _ con
, pat_args = ps
, pat_con_ext = ConPatTc
{ cpt_arg_tys = arg_tys
, cpt_tvs = ex_tvs
, cpt_dicts = dicts
}
} ->
desugarConPatOut x con arg_tys ex_tvs dicts ps
NPat ty (L _ olit) mb_neg _ -> do
dflags <- getDynFlags
let platform = targetPlatform dflags
pm_lit <- case olit of
OverLit{ ol_val = val, ol_ext = OverLitTc rebindable _ }
| not rebindable
, Just expr <- shortCutLit platform val ty
-> coreExprAsPmLit <$> dsExpr expr
| not rebindable
, (HsFractional f) <- val
, negates <- if fl_neg f then 1 else 0
-> do
rat_tc <- dsLookupTyCon rationalTyConName
let rat_ty = mkTyConTy rat_tc
return $ Just $ PmLit rat_ty (PmLitOverRat negates f)
| otherwise
-> do
dsLit <- dsOverLit olit
let !pmLit = coreExprAsPmLit dsLit :: Maybe PmLit
return pmLit
let lit = case pm_lit of
Just l -> l
Nothing -> pprPanic "failed to detect OverLit" (ppr olit)
let lit' = case mb_neg of
Just _ -> expectJust "failed to negate lit" (negatePmLit lit)
Nothing -> lit
mkPmLitGrds x lit'
LitPat _ lit -> do
core_expr <- dsLit (convertLit lit)
let lit = expectJust "failed to detect Lit" (coreExprAsPmLit core_expr)
mkPmLitGrds x lit
TuplePat _tys pats boxity -> do
(vars, grdss) <- mapAndUnzipM desugarLPatV pats
let tuple_con = tupleDataCon boxity (length vars)
pure $ vanillaConGrd x tuple_con vars : concat grdss
SumPat _ty p alt arity -> do
(y, grds) <- desugarLPatV p
let sum_con = sumDataCon alt arity
pure $ vanillaConGrd x sum_con [y] : grds
SplicePat {} -> panic "Check.desugarPat: SplicePat"
desugarPatV :: Pat GhcTc -> DsM (Id, [PmGrd])
desugarPatV pat = do
x <- selectMatchVar Many pat
grds <- desugarPat x pat
pure (x, grds)
desugarLPat :: Id -> LPat GhcTc -> DsM [PmGrd]
desugarLPat x = desugarPat x . unLoc
desugarLPatV :: LPat GhcTc -> DsM (Id, [PmGrd])
desugarLPatV = desugarPatV . unLoc
desugarListPat :: Id -> [LPat GhcTc] -> DsM [PmGrd]
desugarListPat x pats = do
vars_and_grdss <- traverse desugarLPatV pats
mkListGrds x vars_and_grdss
desugarConPatOut :: Id -> ConLike -> [Type] -> [TyVar]
-> [EvVar] -> HsConPatDetails GhcTc -> DsM [PmGrd]
desugarConPatOut x con univ_tys ex_tvs dicts = \case
PrefixCon _ ps -> go_field_pats (zip [0..] ps)
InfixCon p1 p2 -> go_field_pats (zip [0..] [p1,p2])
RecCon (HsRecFields fs _) -> go_field_pats (rec_field_ps fs)
where
arg_tys = map scaledThing $ conLikeInstOrigArgTys con (univ_tys ++ mkTyVarTys ex_tvs)
rec_field_ps fs = map (tagged_pat . unLoc) fs
where
tagged_pat f = (lbl_to_index (getName (hsRecFieldId f)), hsRecFieldArg f)
orig_lbls = map flSelector $ conLikeFieldLabels con
lbl_to_index lbl = expectJust "lbl_to_index" $ elemIndex lbl orig_lbls
go_field_pats tagged_pats = do
let trans_pat (n, pat) = do
(var, pvec) <- desugarLPatV pat
pure ((n, var), pvec)
(tagged_vars, arg_grdss) <- mapAndUnzipM trans_pat tagged_pats
let get_pat_id n ty = case lookup n tagged_vars of
Just var -> pure var
Nothing -> mkPmId ty
arg_ids <- zipWithM get_pat_id [0..] arg_tys
let con_grd = PmCon x (PmAltConLike con) ex_tvs dicts arg_ids
let arg_grds = concat arg_grdss
pure (con_grd : arg_grds)
desugarPatBind :: SrcSpan -> Id -> Pat GhcTc -> DsM (PmPatBind Pre)
desugarPatBind loc var pat =
PmPatBind . flip PmGRHS (SrcInfo (L loc (ppr pat))) . GrdVec <$> desugarPat var pat
desugarEmptyCase :: Id -> DsM PmEmptyCase
desugarEmptyCase var = pure PmEmptyCase { pe_var = var }
desugarMatches :: [Id] -> NonEmpty (LMatch GhcTc (LHsExpr GhcTc))
-> DsM (PmMatchGroup Pre)
desugarMatches vars matches =
PmMatchGroup <$> traverse (desugarMatch vars) matches
desugarMatch :: [Id] -> LMatch GhcTc (LHsExpr GhcTc) -> DsM (PmMatch Pre)
desugarMatch vars (L match_loc (Match { m_pats = pats, m_grhss = grhss })) = do
pats' <- concat <$> zipWithM desugarLPat vars pats
grhss' <- desugarGRHSs (locA match_loc) (sep (map ppr pats)) grhss
return PmMatch { pm_pats = GrdVec pats', pm_grhss = grhss' }
desugarGRHSs :: SrcSpan -> SDoc -> GRHSs GhcTc (LHsExpr GhcTc) -> DsM (PmGRHSs Pre)
desugarGRHSs match_loc pp_pats grhss = do
lcls <- desugarLocalBinds (grhssLocalBinds grhss)
grhss' <- traverse (desugarLGRHS match_loc pp_pats)
. expectJust "desugarGRHSs"
. NE.nonEmpty
$ grhssGRHSs grhss
return PmGRHSs { pgs_lcls = GrdVec lcls, pgs_grhss = grhss' }
desugarLGRHS :: SrcSpan -> SDoc -> LGRHS GhcTc (LHsExpr GhcTc) -> DsM (PmGRHS Pre)
desugarLGRHS match_loc pp_pats (L _loc (GRHS _ gs _)) = do
let rhs_info = case gs of
[] -> L match_loc pp_pats
(L grd_loc _):_ -> L (locA grd_loc) (pp_pats <+> vbar <+> interpp'SP gs)
grds <- concatMapM (desugarGuard . unLoc) gs
pure PmGRHS { pg_grds = GrdVec grds, pg_rhs = SrcInfo rhs_info }
desugarGuard :: GuardStmt GhcTc -> DsM [PmGrd]
desugarGuard guard = case guard of
BodyStmt _ e _ _ -> desugarBoolGuard e
LetStmt _ binds -> desugarLocalBinds binds
BindStmt _ p e -> desugarBind p e
LastStmt {} -> panic "desugarGuard LastStmt"
ParStmt {} -> panic "desugarGuard ParStmt"
TransStmt {} -> panic "desugarGuard TransStmt"
RecStmt {} -> panic "desugarGuard RecStmt"
ApplicativeStmt {} -> panic "desugarGuard ApplicativeLastStmt"
desugarLocalBinds :: HsLocalBinds GhcTc -> DsM [PmGrd]
desugarLocalBinds (HsValBinds _ (XValBindsLR (NValBinds binds _))) =
concatMapM (concatMapM go . bagToList) (map snd binds)
where
go :: LHsBind GhcTc -> DsM [PmGrd]
go (L _ FunBind{fun_id = L _ x, fun_matches = mg})
| L _ [L _ Match{m_pats = [], m_grhss = grhss}] <- mg_alts mg
, GRHSs{grhssGRHSs = [L _ (GRHS _ _grds rhs)]} <- grhss = do
core_rhs <- dsLExpr rhs
return [PmLet x core_rhs]
go (L _ AbsBinds{ abs_tvs = [], abs_ev_vars = []
, abs_exports=exports, abs_binds = binds }) = do
let go_export :: ABExport GhcTc -> Maybe PmGrd
go_export ABE{abe_poly = x, abe_mono = y, abe_wrap = wrap}
| isIdHsWrapper wrap
= ASSERT2(idType x `eqType` idType y, ppr x $$ ppr (idType x) $$ ppr y $$ ppr (idType y))
Just $ PmLet x (Var y)
| otherwise
= Nothing
let exps = mapMaybe go_export exports
bs <- concatMapM go (bagToList binds)
return (exps ++ bs)
go _ = return []
desugarLocalBinds _binds = return []
desugarBind :: LPat GhcTc -> LHsExpr GhcTc -> DsM [PmGrd]
desugarBind p e = dsLExpr e >>= \case
Var y
| Nothing <- isDataConId_maybe y
-> desugarLPat y p
rhs -> do
(x, grds) <- desugarLPatV p
pure (PmLet x rhs : grds)
desugarBoolGuard :: LHsExpr GhcTc -> DsM [PmGrd]
desugarBoolGuard e
| isJust (isTrueLHsExpr e) = return []
| otherwise = dsLExpr e >>= \case
Var y
| Nothing <- isDataConId_maybe y
-> pure [vanillaConGrd y trueDataCon []]
rhs -> do
x <- mkPmId boolTy
pure [PmLet x rhs, vanillaConGrd x trueDataCon []]