packages feed

ghc-lib 0.20221101 → 0.20221201

raw patch · 233 files changed

+22609/−2968 lines, 233 filesdep ~ghc-lib-parserPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: ghc-lib-parser

API changes (from Hackage documentation)

- GHC: data PrintUnqualified
- GHC: getPrintUnqual :: GhcMonad m => m PrintUnqualified
- GHC: isFunTyCon :: TyCon -> Bool
- GHC: mkPrintUnqualifiedForModule :: GhcMonad m => ModuleInfo -> m (Maybe PrintUnqualified)
- GHC.CmmToAsm: [pprNatCmmDecl] :: NcgImpl statics instr jumpDest -> NatCmmDecl statics instr -> SDoc
- GHC.CmmToAsm.Dwarf.Types: [dwLineLabel] :: DwarfInfo -> SDoc
- GHC.CmmToAsm.Monad: [pprNatCmmDecl] :: NcgImpl statics instr jumpDest -> NatCmmDecl statics instr -> SDoc
- GHC.CmmToAsm.X86.Ppr: pprData :: NCGConfig -> CmmStatic -> SDoc
- GHC.CmmToAsm.X86.Ppr: pprDataItem :: NCGConfig -> CmmLit -> SDoc
- GHC.CmmToAsm.X86.Ppr: pprFormat :: Format -> SDoc
- GHC.CmmToAsm.X86.Ppr: pprImm :: Platform -> Imm -> SDoc
- GHC.Core.Opt.WorkWrap.Utils: badWorker :: Bool
- GHC.Core.Opt.WorkWrap.Utils: goodWorker :: Bool
- GHC.Core.Opt.WorkWrap.Utils: isGoodWorker :: Bool -> Bool
- GHC.Driver.Pipeline.Execute: fixchar :: Char -> Char
- GHC.Driver.Pipeline.Execute: generateMacros :: String -> String -> Version -> String
- GHC.Driver.Pipeline.Execute: generatePackageVersionMacros :: [UnitInfo] -> String
- GHC.HsToCore.Monad: mkPrintUnqualifiedDs :: DsM PrintUnqualified
- GHC.HsToCore.Types: [ds_unqual] :: DsGblEnv -> PrintUnqualified
- GHC.Iface.Binary: BinDictionary :: !FastMutInt -> !IORef (UniqFM FastString (Int, FastString)) -> BinDictionary
- GHC.Iface.Binary: [bin_dict_map] :: BinDictionary -> !IORef (UniqFM FastString (Int, FastString))
- GHC.Iface.Binary: [bin_dict_next] :: BinDictionary -> !FastMutInt
- GHC.Iface.Binary: data BinDictionary
- GHC.Iface.Binary: getDictFastString :: Dictionary -> BinHandle -> IO FastString
- GHC.Iface.Binary: putDictionary :: BinHandle -> Int -> UniqFM FastString (Int, FastString) -> IO ()
- GHC.Iface.Binary: putFastString :: BinDictionary -> BinHandle -> FastString -> IO ()
- GHC.Plugins: InvisArg :: AnonArgFlag
- GHC.Plugins: VisArg :: AnonArgFlag
- GHC.Plugins: appTyArgFlags :: Type -> [Type] -> [ArgFlag]
- GHC.Plugins: binderArgFlag :: VarBndr tv argf -> argf
- GHC.Plugins: binderRelevantType_maybe :: TyCoBinder -> Maybe Type
- GHC.Plugins: classifiesTypeWithValues :: Kind -> Bool
- GHC.Plugins: data AnonArgFlag
- GHC.Plugins: data ArgFlag
- GHC.Plugins: data TyCoBinder
- GHC.Plugins: eqType :: Type -> Type -> Bool
- GHC.Plugins: eqTypeX :: RnEnv2 -> Type -> Type -> Bool
- GHC.Plugins: eqTypes :: [Type] -> [Type] -> Bool
- GHC.Plugins: eqVarBndrs :: RnEnv2 -> [Var] -> [Var] -> Maybe RnEnv2
- GHC.Plugins: funTyCon :: TyCon
- GHC.Plugins: getLevity_maybe :: HasDebugCallStack => Type -> Maybe Type
- GHC.Plugins: getRuntimeRep_maybe :: HasDebugCallStack => Type -> Maybe RuntimeRepType
- GHC.Plugins: isAnonTyCoBinder :: TyCoBinder -> Bool
- GHC.Plugins: isConstraintKindCon :: TyCon -> Bool
- GHC.Plugins: isInvisibleArgFlag :: ArgFlag -> Bool
- GHC.Plugins: isInvisibleBinder :: TyCoBinder -> Bool
- GHC.Plugins: isManyDataConTy :: Mult -> Bool
- GHC.Plugins: isNamedBinder :: TyCoBinder -> Bool
- GHC.Plugins: isOneDataConTy :: Mult -> Bool
- GHC.Plugins: isVisibleArgFlag :: ArgFlag -> Bool
- GHC.Plugins: isVisibleBinder :: TyCoBinder -> Bool
- GHC.Plugins: mkAnonBinder :: AnonArgFlag -> Scaled Type -> TyCoBinder
- GHC.Plugins: mkFunCo :: Role -> CoercionN -> Coercion -> Coercion -> Coercion
- GHC.Plugins: mkInvisFunTyMany :: Type -> Type -> Type
- GHC.Plugins: mkInvisFunTysMany :: [Type] -> Type -> Type
- GHC.Plugins: mkNthCo :: HasDebugCallStack => Role -> Int -> Coercion -> Coercion
- GHC.Plugins: mkNthCoFunCo :: Int -> CoercionN -> Coercion -> Coercion -> Coercion
- GHC.Plugins: mkTyCoVarBinder :: vis -> TyCoVar -> VarBndr TyCoVar vis
- GHC.Plugins: mkTyCoVarBinders :: vis -> [TyCoVar] -> [VarBndr TyCoVar vis]
- GHC.Plugins: mkVisFunTys :: [Scaled Type] -> Type -> Type
- GHC.Plugins: nonDetCmpTc :: TyCon -> TyCon -> Ordering
- GHC.Plugins: nonDetCmpType :: Type -> Type -> Ordering
- GHC.Plugins: nonDetCmpTypeX :: RnEnv2 -> Type -> Type -> Ordering
- GHC.Plugins: nonDetCmpTypes :: [Type] -> [Type] -> Ordering
- GHC.Plugins: nonDetCmpTypesX :: RnEnv2 -> [Type] -> [Type] -> Ordering
- GHC.Plugins: nthCoRole :: Int -> Coercion -> Role
- GHC.Plugins: nthRole :: Role -> TyCon -> Int -> Role
- GHC.Plugins: pattern Many :: Mult
- GHC.Plugins: pattern One :: Mult
- GHC.Plugins: repSplitAppTy_maybe :: HasDebugCallStack => Type -> Maybe (Type, Type)
- GHC.Plugins: repSplitAppTys :: HasDebugCallStack => Type -> (Type, [Type])
- GHC.Plugins: repSplitTyConApp_maybe :: HasDebugCallStack => Type -> Maybe (TyCon, [Type])
- GHC.Plugins: sameVis :: ArgFlag -> ArgFlag -> Bool
- GHC.Plugins: splitForAllInvisTVBinders :: Type -> ([InvisTVBinder], Type)
- GHC.Plugins: splitForAllReqTVBinders :: Type -> ([ReqTVBinder], Type)
- GHC.Plugins: splitForAllTyCoVarBinders :: Type -> ([TyCoVarBinder], Type)
- GHC.Plugins: splitListTyConApp_maybe :: Type -> Maybe Type
- GHC.Plugins: splitTyConAppCo_maybe :: Coercion -> Maybe (TyCon, [Coercion])
- GHC.Plugins: splitVisVarsOfType :: Type -> Pair TyCoVarSet
- GHC.Plugins: splitVisVarsOfTypes :: [Type] -> Pair TyCoVarSet
- GHC.Plugins: tcIsConstraintKind :: Kind -> Bool
- GHC.Plugins: tcIsRuntimeTypeKind :: Kind -> Bool
- GHC.Plugins: tcRepSplitAppTy_maybe :: Type -> Maybe (Type, Type)
- GHC.Plugins: tcRepSplitTyConApp_maybe :: HasDebugCallStack => Type -> Maybe (TyCon, [Type])
- GHC.Plugins: tcReturnsConstraintKind :: Kind -> Bool
- GHC.Plugins: tcTypeKind :: HasDebugCallStack => Type -> Kind
- GHC.Plugins: tcView :: Type -> Maybe Type
- GHC.Plugins: tidyTyCoVarBinder :: TidyEnv -> VarBndr TyCoVar vis -> (TidyEnv, VarBndr TyCoVar vis)
- GHC.Plugins: tidyTyCoVarBinders :: TidyEnv -> [VarBndr TyCoVar vis] -> (TidyEnv, [VarBndr TyCoVar vis])
- GHC.Plugins: tyBinderType :: TyBinder -> Type
- GHC.Plugins: tyCoBinderType :: TyCoBinder -> Type
- GHC.Plugins: tyCoBinderVar_maybe :: TyCoBinder -> Maybe TyCoVar
- GHC.Plugins: tyConAppArgN :: Int -> Type -> Type
- GHC.Plugins: tyConArgFlags :: TyCon -> [Type] -> [ArgFlag]
- GHC.Plugins: tyConBindersTyCoBinders :: [TyConBinder] -> [TyCoBinder]
- GHC.Plugins: type TyCoVarBinder = VarBndr TyCoVar ArgFlag
- GHC.Plugins: unrestrictedFunTyCon :: TyCon
- GHC.Tc.Utils.Monad: getPrintUnqualified :: TcRn PrintUnqualified
+ GHC: Opt_PrintRedundantPromotionTicks :: GeneralFlag
+ GHC: Opt_SuppressStgReps :: GeneralFlag
+ GHC: data NamePprCtx
+ GHC: getNamePprCtx :: GhcMonad m => m NamePprCtx
+ GHC: mkNamePprCtxForModule :: GhcMonad m => ModuleInfo -> m (Maybe NamePprCtx)
+ GHC.Builtin.PrimOps.Casts: getCasts :: PrimRep -> PrimRep -> [(PrimOp, Type)]
+ GHC.Cmm.DebugBlock: pprUnwindTable :: IsLine doc => Platform -> UnwindTable -> doc
+ GHC.Cmm.Reducibility: Irreducible :: Reducibility
+ GHC.Cmm.Reducibility: Reducible :: Reducibility
+ GHC.Cmm.Reducibility: asReducible :: GraphWithDominators CmmNode -> UniqSM (GraphWithDominators CmmNode)
+ GHC.Cmm.Reducibility: data Reducibility
+ GHC.Cmm.Reducibility: instance GHC.Base.Semigroup GHC.Cmm.Reducibility.CmmSuper
+ GHC.Cmm.Reducibility: instance GHC.Classes.Eq GHC.Cmm.Reducibility.Reducibility
+ GHC.Cmm.Reducibility: instance GHC.Data.Graph.Collapse.PureSupernode GHC.Cmm.Reducibility.CmmSuper
+ GHC.Cmm.Reducibility: instance GHC.Data.Graph.Collapse.Supernode GHC.Cmm.Reducibility.CmmSuper GHC.Data.Graph.Collapse.NullCollapseViz
+ GHC.Cmm.Reducibility: instance GHC.Show.Show GHC.Cmm.Reducibility.Reducibility
+ GHC.Cmm.Reducibility: reducibility :: NonLocal node => GraphWithDominators node -> Reducibility
+ GHC.CmmToAsm: [pprNatCmmDeclH] :: NcgImpl statics instr jumpDest -> NatCmmDecl statics instr -> HDoc
+ GHC.CmmToAsm: [pprNatCmmDeclS] :: NcgImpl statics instr jumpDest -> NatCmmDecl statics instr -> SDoc
+ GHC.CmmToAsm.Monad: [pprNatCmmDeclH] :: NcgImpl statics instr jumpDest -> NatCmmDecl statics instr -> HDoc
+ GHC.CmmToAsm.Monad: [pprNatCmmDeclS] :: NcgImpl statics instr jumpDest -> NatCmmDecl statics instr -> SDoc
+ GHC.CmmToAsm.Wasm: ncgWasm :: Platform -> UniqSupply -> ModLocation -> Handle -> Stream IO RawCmmGroup a -> IO a
+ GHC.CmmToAsm.Wasm.Asm: asmTellEverything :: WasmTypeTag w -> WasmCodeGenState w -> WasmAsmM ()
+ GHC.CmmToAsm.Wasm.Asm: execWasmAsmM :: WasmAsmM a -> Builder
+ GHC.CmmToAsm.Wasm.Asm: instance GHC.Base.Applicative GHC.CmmToAsm.Wasm.Asm.WasmAsmM
+ GHC.CmmToAsm.Wasm.Asm: instance GHC.Base.Functor GHC.CmmToAsm.Wasm.Asm.WasmAsmM
+ GHC.CmmToAsm.Wasm.Asm: instance GHC.Base.Monad GHC.CmmToAsm.Wasm.Asm.WasmAsmM
+ GHC.CmmToAsm.Wasm.Asm: instance GHC.Base.Monoid a => GHC.Base.Monoid (GHC.CmmToAsm.Wasm.Asm.WasmAsmM a)
+ GHC.CmmToAsm.Wasm.Asm: instance GHC.Base.Semigroup a => GHC.Base.Semigroup (GHC.CmmToAsm.Wasm.Asm.WasmAsmM a)
+ GHC.CmmToAsm.Wasm.FromCmm: [SomeWasmPostCCall] :: TypeList ts -> (forall post. WasmInstr w (WasmPushes ts post) post) -> SomeWasmPostCCall w
+ GHC.CmmToAsm.Wasm.FromCmm: [SomeWasmPreCCall] :: TypeList ts -> (forall pre. WasmInstr w pre (WasmPushes ts pre)) -> SomeWasmPreCCall w
+ GHC.CmmToAsm.Wasm.FromCmm: alignmentFromCmmSection :: WasmTypeTag w -> CLabel -> Alignment
+ GHC.CmmToAsm.Wasm.FromCmm: alignmentFromWordType :: WasmTypeTag w -> Alignment
+ GHC.CmmToAsm.Wasm.FromCmm: allocDataSection :: DataSection -> WasmCodeGenM w SymName
+ GHC.CmmToAsm.Wasm.FromCmm: data SomeWasmPostCCall w
+ GHC.CmmToAsm.Wasm.FromCmm: data SomeWasmPreCCall w
+ GHC.CmmToAsm.Wasm.FromCmm: dataSectionKindFromCmmSection :: Section -> DataSectionKind
+ GHC.CmmToAsm.Wasm.FromCmm: extendSubword :: Width -> WasmTypeTag t -> WasmExpr w t -> WasmExpr w t
+ GHC.CmmToAsm.Wasm.FromCmm: globalInfoFromCmmGlobalReg :: WasmTypeTag w -> GlobalReg -> Maybe GlobalInfo
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CMO_Bin_Homo :: CLabel -> SymName -> [CmmFormal] -> [CmmActual] -> WasmCodeGenM w (WasmStatements w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CMO_Un_Homo :: CLabel -> SymName -> [CmmFormal] -> [CmmActual] -> WasmCodeGenM w (WasmStatements w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CMO_Un_Prim :: CLabel -> (forall pre t. WasmTypeTag t -> WasmInstr w (t : pre) (t : pre)) -> [CmmFormal] -> [CmmActual] -> WasmCodeGenM w (WasmStatements w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CallishMachOp :: CLabel -> CallishMachOp -> [CmmFormal] -> [CmmActual] -> WasmCodeGenM w (WasmStatements w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmAction :: CLabel -> CmmNode O O -> WasmCodeGenM w (WasmStatements w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmActions :: CLabel -> Label -> Block CmmNode O O -> WasmCodeGenM w (WasmStatements w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmExpr :: CLabel -> CmmExpr -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmExpr_Ptr :: CLabel -> CmmExpr -> WasmCodeGenM w (WasmExpr w w, Int)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmExpr_Typed :: CLabel -> WasmTypeTag t -> CmmExpr -> WasmCodeGenM w (WasmExpr w t)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmGraph :: CLabel -> CmmGraph -> WasmCodeGenM w (FuncBody w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmLit :: CmmLit -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmLoad :: CLabel -> CmmExpr -> CmmType -> AlignmentSpec -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmLoad_Typed :: CLabel -> CmmExpr -> WasmTypeTag t -> CmmType -> AlignmentSpec -> WasmCodeGenM w (WasmExpr w t)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmMachOp :: CLabel -> MachOp -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmReg :: CLabel -> CmmReg -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmRegOff :: CLabel -> CmmReg -> Int -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmStatic :: CmmStatic -> WasmCodeGenM w DataSectionContent
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmStore :: CLabel -> CmmExpr -> CmmExpr -> AlignmentSpec -> WasmCodeGenM w (WasmStatements w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmUnsafeForeignCall :: CLabel -> Either SymName CmmExpr -> CmmReturnInfo -> [CmmFormal] -> [CmmActual] -> WasmCodeGenM w (WasmStatements w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_CmmUnsafeForeignCall_Drop :: CLabel -> SymName -> CmmType -> [CmmActual] -> WasmCodeGenM w (WasmStatements w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_Bin_Homo :: (forall pre t. WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)) -> CLabel -> CmmType -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_Bin_Homo_Ext_Trunc :: (forall pre t. WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)) -> CLabel -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_Bin_Homo_Trunc :: (forall pre t. WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)) -> CLabel -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_Bin_Rel :: (forall pre t. WasmTypeTag t -> WasmInstr w (t : (t : pre)) (w : pre)) -> CLabel -> CmmType -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_Bin_Rel_Ext :: (forall pre t. WasmTypeTag t -> WasmInstr w (t : (t : pre)) (w : pre)) -> CLabel -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_Cmpxchg :: CLabel -> Width -> [CmmFormal] -> [CmmActual] -> WasmCodeGenM w (WasmStatements w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_FF_Conv :: CLabel -> Width -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_MulMayOflo :: CLabel -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_SS_Conv :: CLabel -> Width -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_S_Shr :: CLabel -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_Shl :: CLabel -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_UF_Conv :: CLabel -> Width -> [CmmFormal] -> [CmmActual] -> WasmCodeGenM w (WasmStatements w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_UU_Conv :: CLabel -> Width -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_U_Shr :: CLabel -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: lower_MO_Un_Conv :: (forall pre t0 t1. WasmTypeTag t0 -> WasmTypeTag t1 -> WasmInstr w (t0 : pre) (t1 : pre)) -> CLabel -> CmmType -> CmmType -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)
+ GHC.CmmToAsm.Wasm.FromCmm: onAnySym :: CLabel -> WasmCodeGenM w ()
+ GHC.CmmToAsm.Wasm.FromCmm: onCmmData :: CLabel -> Section -> [CmmStatic] -> WasmCodeGenM w ()
+ GHC.CmmToAsm.Wasm.FromCmm: onCmmDecl :: RawCmmDecl -> WasmCodeGenM w ()
+ GHC.CmmToAsm.Wasm.FromCmm: onCmmGroup :: RawCmmGroup -> WasmCodeGenM w ()
+ GHC.CmmToAsm.Wasm.FromCmm: onCmmInitFini :: InitOrFini -> [CLabel] -> WasmCodeGenM w ()
+ GHC.CmmToAsm.Wasm.FromCmm: onCmmLocalReg :: LocalReg -> WasmCodeGenM w LocalInfo
+ GHC.CmmToAsm.Wasm.FromCmm: onCmmLocalReg_Typed :: WasmTypeTag t -> LocalReg -> WasmCodeGenM w Int
+ GHC.CmmToAsm.Wasm.FromCmm: onCmmProc :: CLabel -> CmmGraph -> WasmCodeGenM w ()
+ GHC.CmmToAsm.Wasm.FromCmm: onFini :: [SymName] -> WasmCodeGenM w ()
+ GHC.CmmToAsm.Wasm.FromCmm: onFuncSym :: SymName -> [CmmType] -> [CmmType] -> WasmCodeGenM w ()
+ GHC.CmmToAsm.Wasm.FromCmm: onTopSym :: CLabel -> WasmCodeGenM w ()
+ GHC.CmmToAsm.Wasm.FromCmm: shiftRHSCast :: CLabel -> WasmTypeTag t -> CmmExpr -> WasmCodeGenM w (WasmExpr w t)
+ GHC.CmmToAsm.Wasm.FromCmm: someWasmTypeFromCmmType :: CmmType -> SomeWasmType
+ GHC.CmmToAsm.Wasm.FromCmm: supportedCmmGlobalRegs :: [GlobalReg]
+ GHC.CmmToAsm.Wasm.FromCmm: symKindFromCLabel :: CLabel -> SymKind
+ GHC.CmmToAsm.Wasm.FromCmm: symNameFromCLabel :: CLabel -> SymName
+ GHC.CmmToAsm.Wasm.FromCmm: symVisibilityFromCLabel :: CLabel -> SymVisibility
+ GHC.CmmToAsm.Wasm.FromCmm: truncSubword :: Width -> WasmTypeTag t -> WasmExpr w t -> WasmExpr w t
+ GHC.CmmToAsm.Wasm.FromCmm: type family WasmPushes (ts :: [WasmType]) (pre :: [WasmType]) :: [WasmType]
+ GHC.CmmToAsm.Wasm.FromCmm: wasmDebugMsg :: String -> WasmCodeGenM w (WasmStatements w)
+ GHC.CmmToAsm.Wasm.FromCmm: wasmMemoryNarrowing :: WasmTypeTag t -> CmmType -> Maybe Int
+ GHC.CmmToAsm.Wasm.Types: BrTableInterval :: Integer -> Integer -> BrTableInterval
+ GHC.CmmToAsm.Wasm.Types: DataASCII :: ByteString -> DataSectionContent
+ GHC.CmmToAsm.Wasm.Types: DataF32 :: Float -> DataSectionContent
+ GHC.CmmToAsm.Wasm.Types: DataF64 :: Double -> DataSectionContent
+ GHC.CmmToAsm.Wasm.Types: DataI16 :: Integer -> DataSectionContent
+ GHC.CmmToAsm.Wasm.Types: DataI32 :: Integer -> DataSectionContent
+ GHC.CmmToAsm.Wasm.Types: DataI64 :: Integer -> DataSectionContent
+ GHC.CmmToAsm.Wasm.Types: DataI8 :: Integer -> DataSectionContent
+ GHC.CmmToAsm.Wasm.Types: DataIncBin :: FilePath -> Int -> DataSectionContent
+ GHC.CmmToAsm.Wasm.Types: DataSection :: DataSectionKind -> Alignment -> [DataSectionContent] -> DataSection
+ GHC.CmmToAsm.Wasm.Types: DataSkip :: Int -> DataSectionContent
+ GHC.CmmToAsm.Wasm.Types: DataSym :: SymName -> Int -> DataSectionContent
+ GHC.CmmToAsm.Wasm.Types: F32 :: WasmType
+ GHC.CmmToAsm.Wasm.Types: F64 :: WasmType
+ GHC.CmmToAsm.Wasm.Types: FuncBody :: [SomeWasmType] -> WasmControl (WasmStatements w) (WasmExpr w w) '[] '[w] -> FuncBody w
+ GHC.CmmToAsm.Wasm.Types: I32 :: WasmType
+ GHC.CmmToAsm.Wasm.Types: I64 :: WasmType
+ GHC.CmmToAsm.Wasm.Types: SectionData :: DataSectionKind
+ GHC.CmmToAsm.Wasm.Types: SectionROData :: DataSectionKind
+ GHC.CmmToAsm.Wasm.Types: Signed :: Signage
+ GHC.CmmToAsm.Wasm.Types: SymData :: SymKind
+ GHC.CmmToAsm.Wasm.Types: SymDefault :: SymVisibility
+ GHC.CmmToAsm.Wasm.Types: SymFunc :: SymKind
+ GHC.CmmToAsm.Wasm.Types: SymName :: FastString -> SymName
+ GHC.CmmToAsm.Wasm.Types: SymStatic :: SymVisibility
+ GHC.CmmToAsm.Wasm.Types: SymUndefined :: SymVisibility
+ GHC.CmmToAsm.Wasm.Types: Unsigned :: Signage
+ GHC.CmmToAsm.Wasm.Types: WasmCodeGenM :: State (WasmCodeGenState w) a -> WasmCodeGenM w a
+ GHC.CmmToAsm.Wasm.Types: WasmCodeGenState :: Platform -> SymSet -> SymMap ([SomeWasmType], [SomeWasmType]) -> SymMap (FuncBody w) -> SymMap DataSection -> [SymName] -> UniqFM LocalReg LocalInfo -> Int -> UniqSupply -> WasmCodeGenState w
+ GHC.CmmToAsm.Wasm.Types: WasmExpr :: (forall pre. WasmInstr w pre (t : pre)) -> WasmExpr w t
+ GHC.CmmToAsm.Wasm.Types: WasmFunctionType :: TypeList pre -> TypeList post -> WasmFunctionType pre post
+ GHC.CmmToAsm.Wasm.Types: WasmStatements :: (forall pre. WasmInstr w pre pre) -> WasmStatements w
+ GHC.CmmToAsm.Wasm.Types: [SomeWasmExpr] :: WasmTypeTag t -> WasmExpr w t -> SomeWasmExpr w
+ GHC.CmmToAsm.Wasm.Types: [SomeWasmType] :: WasmTypeTag t -> SomeWasmType
+ GHC.CmmToAsm.Wasm.Types: [TagF32] :: WasmTypeTag 'F32
+ GHC.CmmToAsm.Wasm.Types: [TagF64] :: WasmTypeTag 'F64
+ GHC.CmmToAsm.Wasm.Types: [TagI32] :: WasmTypeTag 'I32
+ GHC.CmmToAsm.Wasm.Types: [TagI64] :: WasmTypeTag 'I64
+ GHC.CmmToAsm.Wasm.Types: [TypeListCons] :: WasmTypeTag t -> TypeList ts -> TypeList (t : ts)
+ GHC.CmmToAsm.Wasm.Types: [TypeListNil] :: TypeList '[]
+ GHC.CmmToAsm.Wasm.Types: [WasmAbs] :: WasmTypeTag t -> WasmInstr w (t : pre) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmActions] :: s -> WasmControl s e stack stack
+ GHC.CmmToAsm.Wasm.Types: [WasmAdd] :: WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmAnd] :: WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmBlock] :: WasmFunctionType pre post -> WasmControl s e pre post -> WasmControl s e pre post
+ GHC.CmmToAsm.Wasm.Types: [WasmBrTable] :: e -> BrTableInterval -> [Int] -> Int -> WasmControl s e dropped destination
+ GHC.CmmToAsm.Wasm.Types: [WasmBr] :: Int -> WasmControl s e dropped destination
+ GHC.CmmToAsm.Wasm.Types: [WasmCCallIndirect] :: TypeList arg_tys -> TypeList ret_tys -> WasmInstr w (w : pre) post
+ GHC.CmmToAsm.Wasm.Types: [WasmCCall] :: SymName -> WasmInstr w pre post
+ GHC.CmmToAsm.Wasm.Types: [WasmComment] :: String -> WasmInstr w pre pre
+ GHC.CmmToAsm.Wasm.Types: [WasmConcat] :: WasmInstr w pre mid -> WasmInstr w mid post -> WasmInstr w pre post
+ GHC.CmmToAsm.Wasm.Types: [WasmCond] :: WasmInstr w pre pre -> WasmInstr w (w : pre) pre
+ GHC.CmmToAsm.Wasm.Types: [WasmConst] :: WasmTypeTag t -> Integer -> WasmInstr w pre (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmConvert] :: Signage -> WasmTypeTag t0 -> WasmTypeTag t1 -> WasmInstr w (t0 : pre) (t1 : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmDiv] :: Signage -> WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmDrop] :: WasmInstr w (t : pre) pre
+ GHC.CmmToAsm.Wasm.Types: [WasmEq] :: WasmTypeTag t -> WasmInstr w (t : (t : pre)) (w : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmF32DemoteF64] :: WasmInstr w ('F64 : pre) ('F32 : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmF64PromoteF32] :: WasmInstr w ('F32 : pre) ('F64 : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmFallthrough] :: WasmControl s e dropped destination
+ GHC.CmmToAsm.Wasm.Types: [WasmGe] :: Signage -> WasmTypeTag t -> WasmInstr w (t : (t : pre)) (w : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmGlobalGet] :: WasmTypeTag t -> SymName -> WasmInstr w pre (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmGlobalSet] :: WasmTypeTag t -> SymName -> WasmInstr w (t : pre) pre
+ GHC.CmmToAsm.Wasm.Types: [WasmGt] :: Signage -> WasmTypeTag t -> WasmInstr w (t : (t : pre)) (w : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmI32Extend16S] :: WasmInstr w ('I32 : pre) ('I32 : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmI32Extend8S] :: WasmInstr w ('I32 : pre) ('I32 : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmI32WrapI64] :: WasmInstr w ('I64 : pre) ('I32 : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmI64Extend16S] :: WasmInstr w ('I64 : pre) ('I64 : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmI64Extend32S] :: WasmInstr w ('I64 : pre) ('I64 : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmI64Extend8S] :: WasmInstr w ('I64 : pre) ('I64 : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmI64ExtendI32] :: Signage -> WasmInstr w ('I32 : pre) ('I64 : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmIfTop] :: WasmFunctionType pre post -> WasmControl s e pre post -> WasmControl s e pre post -> WasmControl s e ('I32 : pre) post
+ GHC.CmmToAsm.Wasm.Types: [WasmLe] :: Signage -> WasmTypeTag t -> WasmInstr w (t : (t : pre)) (w : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmLoad] :: WasmTypeTag t -> Maybe Int -> Signage -> Int -> AlignmentSpec -> WasmInstr w (w : pre) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmLocalGet] :: WasmTypeTag t -> Int -> WasmInstr w pre (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmLocalSet] :: WasmTypeTag t -> Int -> WasmInstr w (t : pre) pre
+ GHC.CmmToAsm.Wasm.Types: [WasmLocalTee] :: WasmTypeTag t -> Int -> WasmInstr w (t : pre) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmLoop] :: WasmFunctionType pre post -> WasmControl s e pre post -> WasmControl s e pre post
+ GHC.CmmToAsm.Wasm.Types: [WasmLt] :: Signage -> WasmTypeTag t -> WasmInstr w (t : (t : pre)) (w : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmMul] :: WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmNe] :: WasmTypeTag t -> WasmInstr w (t : (t : pre)) (w : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmNop] :: WasmInstr w pre pre
+ GHC.CmmToAsm.Wasm.Types: [WasmOr] :: WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmPush] :: WasmTypeTag t -> e -> WasmControl s e stack (t : stack)
+ GHC.CmmToAsm.Wasm.Types: [WasmReinterpret] :: WasmTypeTag t0 -> WasmTypeTag t1 -> WasmInstr w (t0 : pre) (t1 : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmRem] :: Signage -> WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmReturnTop] :: WasmTypeTag t -> WasmControl s e (t : t1star) t2star
+ GHC.CmmToAsm.Wasm.Types: [WasmSeq] :: WasmControl s e pre mid -> WasmControl s e mid post -> WasmControl s e pre post
+ GHC.CmmToAsm.Wasm.Types: [WasmShl] :: WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmShr] :: Signage -> WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmStore] :: WasmTypeTag t -> Maybe Int -> Int -> AlignmentSpec -> WasmInstr w (t : (w : pre)) pre
+ GHC.CmmToAsm.Wasm.Types: [WasmSub] :: WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmSymConst] :: SymName -> WasmInstr w pre (w : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmTruncSat] :: Signage -> WasmTypeTag t0 -> WasmTypeTag t1 -> WasmInstr w (t0 : pre) (t1 : pre)
+ GHC.CmmToAsm.Wasm.Types: [WasmUnreachable] :: WasmInstr w pre post
+ GHC.CmmToAsm.Wasm.Types: [WasmXor] :: WasmTypeTag t -> WasmInstr w (t : (t : pre)) (t : pre)
+ GHC.CmmToAsm.Wasm.Types: [bti_count] :: BrTableInterval -> Integer
+ GHC.CmmToAsm.Wasm.Types: [bti_lo] :: BrTableInterval -> Integer
+ GHC.CmmToAsm.Wasm.Types: [ctors] :: WasmCodeGenState w -> [SymName]
+ GHC.CmmToAsm.Wasm.Types: [dataSectionAlignment] :: DataSection -> Alignment
+ GHC.CmmToAsm.Wasm.Types: [dataSectionContents] :: DataSection -> [DataSectionContent]
+ GHC.CmmToAsm.Wasm.Types: [dataSectionKind] :: DataSection -> DataSectionKind
+ GHC.CmmToAsm.Wasm.Types: [dataSections] :: WasmCodeGenState w -> SymMap DataSection
+ GHC.CmmToAsm.Wasm.Types: [defaultSyms] :: WasmCodeGenState w -> SymSet
+ GHC.CmmToAsm.Wasm.Types: [ft_pops] :: WasmFunctionType pre post -> TypeList pre
+ GHC.CmmToAsm.Wasm.Types: [ft_pushes] :: WasmFunctionType pre post -> TypeList post
+ GHC.CmmToAsm.Wasm.Types: [funcBodies] :: WasmCodeGenState w -> SymMap (FuncBody w)
+ GHC.CmmToAsm.Wasm.Types: [funcBody] :: FuncBody w -> WasmControl (WasmStatements w) (WasmExpr w w) '[] '[w]
+ GHC.CmmToAsm.Wasm.Types: [funcLocals] :: FuncBody w -> [SomeWasmType]
+ GHC.CmmToAsm.Wasm.Types: [funcTypes] :: WasmCodeGenState w -> SymMap ([SomeWasmType], [SomeWasmType])
+ GHC.CmmToAsm.Wasm.Types: [localRegsCount] :: WasmCodeGenState w -> Int
+ GHC.CmmToAsm.Wasm.Types: [localRegs] :: WasmCodeGenState w -> UniqFM LocalReg LocalInfo
+ GHC.CmmToAsm.Wasm.Types: [wasmPlatform] :: WasmCodeGenState w -> Platform
+ GHC.CmmToAsm.Wasm.Types: [wasmUniqSupply] :: WasmCodeGenState w -> UniqSupply
+ GHC.CmmToAsm.Wasm.Types: data BrTableInterval
+ GHC.CmmToAsm.Wasm.Types: data DataSection
+ GHC.CmmToAsm.Wasm.Types: data DataSectionContent
+ GHC.CmmToAsm.Wasm.Types: data DataSectionKind
+ GHC.CmmToAsm.Wasm.Types: data FuncBody w
+ GHC.CmmToAsm.Wasm.Types: data Signage
+ GHC.CmmToAsm.Wasm.Types: data SomeWasmExpr w
+ GHC.CmmToAsm.Wasm.Types: data SomeWasmType
+ GHC.CmmToAsm.Wasm.Types: data SymKind
+ GHC.CmmToAsm.Wasm.Types: data SymVisibility
+ GHC.CmmToAsm.Wasm.Types: data TypeList :: [WasmType] -> Type
+ GHC.CmmToAsm.Wasm.Types: data WasmCodeGenState w
+ GHC.CmmToAsm.Wasm.Types: data WasmControl :: Type -> Type -> [WasmType] -> [WasmType] -> Type
+ GHC.CmmToAsm.Wasm.Types: data WasmFunctionType pre post
+ GHC.CmmToAsm.Wasm.Types: data WasmInstr :: WasmType -> [WasmType] -> [WasmType] -> Type
+ GHC.CmmToAsm.Wasm.Types: data WasmType
+ GHC.CmmToAsm.Wasm.Types: data WasmTypeTag :: WasmType -> Type
+ GHC.CmmToAsm.Wasm.Types: initialWasmCodeGenState :: Platform -> UniqSupply -> WasmCodeGenState w
+ GHC.CmmToAsm.Wasm.Types: instance Data.String.IsString GHC.CmmToAsm.Wasm.Types.SymName
+ GHC.CmmToAsm.Wasm.Types: instance Data.Type.Equality.TestEquality GHC.CmmToAsm.Wasm.Types.WasmTypeTag
+ GHC.CmmToAsm.Wasm.Types: instance GHC.Base.Applicative (GHC.CmmToAsm.Wasm.Types.WasmCodeGenM w)
+ GHC.CmmToAsm.Wasm.Types: instance GHC.Base.Functor (GHC.CmmToAsm.Wasm.Types.WasmCodeGenM w)
+ GHC.CmmToAsm.Wasm.Types: instance GHC.Base.Monad (GHC.CmmToAsm.Wasm.Types.WasmCodeGenM w)
+ GHC.CmmToAsm.Wasm.Types: instance GHC.Classes.Eq GHC.CmmToAsm.Wasm.Types.SomeWasmType
+ GHC.CmmToAsm.Wasm.Types: instance GHC.Classes.Eq GHC.CmmToAsm.Wasm.Types.SymKind
+ GHC.CmmToAsm.Wasm.Types: instance GHC.Classes.Eq GHC.CmmToAsm.Wasm.Types.SymName
+ GHC.CmmToAsm.Wasm.Types: instance GHC.Classes.Ord GHC.CmmToAsm.Wasm.Types.SymName
+ GHC.CmmToAsm.Wasm.Types: instance GHC.Show.Show (GHC.CmmToAsm.Wasm.Types.WasmTypeTag t)
+ GHC.CmmToAsm.Wasm.Types: instance GHC.Show.Show GHC.CmmToAsm.Wasm.Types.BrTableInterval
+ GHC.CmmToAsm.Wasm.Types: instance GHC.Show.Show GHC.CmmToAsm.Wasm.Types.SymName
+ GHC.CmmToAsm.Wasm.Types: instance GHC.Types.Unique.Uniquable GHC.CmmToAsm.Wasm.Types.SymName
+ GHC.CmmToAsm.Wasm.Types: instance GHC.Utils.Outputable.Outputable GHC.CmmToAsm.Wasm.Types.BrTableInterval
+ GHC.CmmToAsm.Wasm.Types: newtype SymName
+ GHC.CmmToAsm.Wasm.Types: newtype WasmCodeGenM w a
+ GHC.CmmToAsm.Wasm.Types: newtype WasmExpr w t
+ GHC.CmmToAsm.Wasm.Types: newtype WasmStatements w
+ GHC.CmmToAsm.Wasm.Types: someWasmTypesFromTypeList :: TypeList ts -> [SomeWasmType]
+ GHC.CmmToAsm.Wasm.Types: type GlobalInfo = (SymName, SomeWasmType)
+ GHC.CmmToAsm.Wasm.Types: type LocalInfo = (Int, SomeWasmType)
+ GHC.CmmToAsm.Wasm.Types: wasmControlCast :: WasmControl s e pre post -> WasmControl s e pre' post'
+ GHC.CmmToAsm.Wasm.Types: wasmExecM :: WasmCodeGenM w a -> WasmCodeGenState w -> WasmCodeGenState w
+ GHC.CmmToAsm.Wasm.Types: wasmGetsM :: (WasmCodeGenState w -> a) -> WasmCodeGenM w a
+ GHC.CmmToAsm.Wasm.Types: wasmModifyM :: (WasmCodeGenState w -> WasmCodeGenState w) -> WasmCodeGenM w ()
+ GHC.CmmToAsm.Wasm.Types: wasmPlatformM :: WasmCodeGenM w Platform
+ GHC.CmmToAsm.Wasm.Types: wasmStateM :: (WasmCodeGenState w -> (# a, WasmCodeGenState w #)) -> WasmCodeGenM w a
+ GHC.CmmToAsm.Wasm.Types: wasmUniq :: WasmCodeGenM w Unique
+ GHC.CmmToAsm.Wasm.Types: wasmWordCmmTypeM :: WasmCodeGenM w CmmType
+ GHC.CmmToAsm.Wasm.Types: wasmWordTypeM :: WasmCodeGenM w (WasmTypeTag w)
+ GHC.CmmToAsm.Wasm.Utils: builderCommas :: (a -> Builder) -> [a] -> Builder
+ GHC.CmmToAsm.Wasm.Utils: detEltsUFM :: Ord k => UniqFM k0 (k, a) -> [(k, a)]
+ GHC.CmmToAsm.Wasm.Utils: detEltsUniqMap :: Ord k => UniqMap k a -> [(k, a)]
+ GHC.CmmToAsm.Wasm.Utils: naturalNarrowing :: Width -> Integer -> Integer
+ GHC.CmmToAsm.Wasm.Utils: widthMax :: Width -> Integer
+ GHC.Core.Opt.WorkWrap.Utils: boringSplit :: WwUse
+ GHC.Core.Opt.WorkWrap.Utils: usefulSplit :: WwUse
+ GHC.Data.Graph.Collapse: NullCollapseViz :: UniqSM a -> NullCollapseViz a
+ GHC.Data.Graph.Collapse: [unNCV] :: NullCollapseViz a -> UniqSM a
+ GHC.Data.Graph.Collapse: class (Monad m) => MonadUniqSM m
+ GHC.Data.Graph.Collapse: class (Semigroup node) => PureSupernode node
+ GHC.Data.Graph.Collapse: class (MonadUnique m, PureSupernode node) => Supernode node m
+ GHC.Data.Graph.Collapse: class (MonadUniqSM m, Graph gr, Supernode s m) => VizCollapseMonad m gr s
+ GHC.Data.Graph.Collapse: collapseInductiveGraph :: (DynGraph gr, Supernode s m, VizCollapseMonad m gr s) => gr s () -> m (gr s ())
+ GHC.Data.Graph.Collapse: consumeByInGraph :: VizCollapseMonad m gr s => Node -> Node -> gr s () -> m ()
+ GHC.Data.Graph.Collapse: finalGraph :: VizCollapseMonad m gr s => gr s () -> m ()
+ GHC.Data.Graph.Collapse: freshen :: Supernode node m => node -> m node
+ GHC.Data.Graph.Collapse: instance (GHC.Data.Graph.Inductive.Graph.Graph gr, GHC.Data.Graph.Collapse.Supernode s GHC.Data.Graph.Collapse.NullCollapseViz) => GHC.Data.Graph.Collapse.VizCollapseMonad GHC.Data.Graph.Collapse.NullCollapseViz gr s
+ GHC.Data.Graph.Collapse: instance GHC.Base.Applicative GHC.Data.Graph.Collapse.NullCollapseViz
+ GHC.Data.Graph.Collapse: instance GHC.Base.Functor GHC.Data.Graph.Collapse.NullCollapseViz
+ GHC.Data.Graph.Collapse: instance GHC.Base.Monad GHC.Data.Graph.Collapse.NullCollapseViz
+ GHC.Data.Graph.Collapse: instance GHC.Data.Graph.Collapse.MonadUniqSM GHC.Data.Graph.Collapse.NullCollapseViz
+ GHC.Data.Graph.Collapse: instance GHC.Types.Unique.Supply.MonadUnique GHC.Data.Graph.Collapse.NullCollapseViz
+ GHC.Data.Graph.Collapse: liftUniqSM :: MonadUniqSM m => UniqSM a -> m a
+ GHC.Data.Graph.Collapse: mapLabels :: PureSupernode node => (Label -> Label) -> node -> node
+ GHC.Data.Graph.Collapse: newtype NullCollapseViz a
+ GHC.Data.Graph.Collapse: runNullCollapse :: NullCollapseViz a -> UniqSM a
+ GHC.Data.Graph.Collapse: splitGraphAt :: VizCollapseMonad m gr s => gr s () -> LNode s -> m ()
+ GHC.Data.Graph.Collapse: superLabel :: PureSupernode node => node -> Label
+ GHC.Data.Graph.Inductive.Graph: (&) :: DynGraph gr => Context a b -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: LP :: [LNode a] -> LPath a
+ GHC.Data.Graph.Inductive.Graph: OrdGr :: gr a b -> OrdGr gr a b
+ GHC.Data.Graph.Inductive.Graph: [unLPath] :: LPath a -> [LNode a]
+ GHC.Data.Graph.Inductive.Graph: [unOrdGr] :: OrdGr gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: buildGr :: DynGraph gr => [Context a b] -> gr a b
+ GHC.Data.Graph.Inductive.Graph: class (Graph gr) => DynGraph gr
+ GHC.Data.Graph.Inductive.Graph: class Graph gr
+ GHC.Data.Graph.Inductive.Graph: context :: Graph gr => gr a b -> Node -> Context a b
+ GHC.Data.Graph.Inductive.Graph: deg :: Graph gr => gr a b -> Node -> Int
+ GHC.Data.Graph.Inductive.Graph: deg' :: Context a b -> Int
+ GHC.Data.Graph.Inductive.Graph: delAllLEdge :: (DynGraph gr, Eq b) => LEdge b -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: delEdge :: DynGraph gr => Edge -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: delEdges :: DynGraph gr => [Edge] -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: delLEdge :: (DynGraph gr, Eq b) => LEdge b -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: delNode :: Graph gr => Node -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: delNodes :: Graph gr => [Node] -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: edgeLabel :: LEdge b -> b
+ GHC.Data.Graph.Inductive.Graph: edges :: Graph gr => gr a b -> [Edge]
+ GHC.Data.Graph.Inductive.Graph: emap :: DynGraph gr => (b -> c) -> gr a b -> gr a c
+ GHC.Data.Graph.Inductive.Graph: empty :: Graph gr => gr a b
+ GHC.Data.Graph.Inductive.Graph: equal :: (Eq a, Eq b, Graph gr) => gr a b -> gr a b -> Bool
+ GHC.Data.Graph.Inductive.Graph: gelem :: Graph gr => Node -> gr a b -> Bool
+ GHC.Data.Graph.Inductive.Graph: gfiltermap :: DynGraph gr => (Context a b -> MContext c d) -> gr a b -> gr c d
+ GHC.Data.Graph.Inductive.Graph: gmap :: DynGraph gr => (Context a b -> Context c d) -> gr a b -> gr c d
+ GHC.Data.Graph.Inductive.Graph: hasEdge :: Graph gr => gr a b -> Edge -> Bool
+ GHC.Data.Graph.Inductive.Graph: hasLEdge :: (Graph gr, Eq b) => gr a b -> LEdge b -> Bool
+ GHC.Data.Graph.Inductive.Graph: hasNeighbor :: Graph gr => gr a b -> Node -> Node -> Bool
+ GHC.Data.Graph.Inductive.Graph: hasNeighborAdj :: (Graph gr, Eq b) => gr a b -> Node -> (b, Node) -> Bool
+ GHC.Data.Graph.Inductive.Graph: indeg :: Graph gr => gr a b -> Node -> Int
+ GHC.Data.Graph.Inductive.Graph: indeg' :: Context a b -> Int
+ GHC.Data.Graph.Inductive.Graph: inn :: Graph gr => gr a b -> Node -> [LEdge b]
+ GHC.Data.Graph.Inductive.Graph: inn' :: Context a b -> [LEdge b]
+ GHC.Data.Graph.Inductive.Graph: insEdge :: DynGraph gr => LEdge b -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: insEdges :: DynGraph gr => [LEdge b] -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: insNode :: DynGraph gr => LNode a -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: insNodes :: DynGraph gr => [LNode a] -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: instance (GHC.Data.Graph.Inductive.Graph.Graph gr, GHC.Classes.Ord a, GHC.Classes.Ord b) => GHC.Classes.Eq (GHC.Data.Graph.Inductive.Graph.OrdGr gr a b)
+ GHC.Data.Graph.Inductive.Graph: instance (GHC.Data.Graph.Inductive.Graph.Graph gr, GHC.Classes.Ord a, GHC.Classes.Ord b) => GHC.Classes.Ord (GHC.Data.Graph.Inductive.Graph.OrdGr gr a b)
+ GHC.Data.Graph.Inductive.Graph: instance GHC.Classes.Eq a => GHC.Classes.Eq (GHC.Data.Graph.Inductive.Graph.LPath a)
+ GHC.Data.Graph.Inductive.Graph: instance GHC.Classes.Eq b => GHC.Classes.Eq (GHC.Data.Graph.Inductive.Graph.GroupEdges b)
+ GHC.Data.Graph.Inductive.Graph: instance GHC.Classes.Ord a => GHC.Classes.Ord (GHC.Data.Graph.Inductive.Graph.LPath a)
+ GHC.Data.Graph.Inductive.Graph: instance GHC.Read.Read (gr a b) => GHC.Read.Read (GHC.Data.Graph.Inductive.Graph.OrdGr gr a b)
+ GHC.Data.Graph.Inductive.Graph: instance GHC.Read.Read b => GHC.Read.Read (GHC.Data.Graph.Inductive.Graph.GroupEdges b)
+ GHC.Data.Graph.Inductive.Graph: instance GHC.Show.Show (gr a b) => GHC.Show.Show (GHC.Data.Graph.Inductive.Graph.OrdGr gr a b)
+ GHC.Data.Graph.Inductive.Graph: instance GHC.Show.Show a => GHC.Show.Show (GHC.Data.Graph.Inductive.Graph.LPath a)
+ GHC.Data.Graph.Inductive.Graph: instance GHC.Show.Show b => GHC.Show.Show (GHC.Data.Graph.Inductive.Graph.GroupEdges b)
+ GHC.Data.Graph.Inductive.Graph: isEmpty :: Graph gr => gr a b -> Bool
+ GHC.Data.Graph.Inductive.Graph: lab :: Graph gr => gr a b -> Node -> Maybe a
+ GHC.Data.Graph.Inductive.Graph: lab' :: Context a b -> a
+ GHC.Data.Graph.Inductive.Graph: labEdges :: Graph gr => gr a b -> [LEdge b]
+ GHC.Data.Graph.Inductive.Graph: labNode' :: Context a b -> LNode a
+ GHC.Data.Graph.Inductive.Graph: labNodes :: Graph gr => gr a b -> [LNode a]
+ GHC.Data.Graph.Inductive.Graph: labfilter :: DynGraph gr => (a -> Bool) -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: labnfilter :: Graph gr => (LNode a -> Bool) -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: lneighbors :: Graph gr => gr a b -> Node -> Adj b
+ GHC.Data.Graph.Inductive.Graph: lneighbors' :: Context a b -> Adj b
+ GHC.Data.Graph.Inductive.Graph: lpre :: Graph gr => gr a b -> Node -> [(Node, b)]
+ GHC.Data.Graph.Inductive.Graph: lpre' :: Context a b -> [(Node, b)]
+ GHC.Data.Graph.Inductive.Graph: lsuc :: Graph gr => gr a b -> Node -> [(Node, b)]
+ GHC.Data.Graph.Inductive.Graph: lsuc' :: Context a b -> [(Node, b)]
+ GHC.Data.Graph.Inductive.Graph: match :: Graph gr => Node -> gr a b -> Decomp gr a b
+ GHC.Data.Graph.Inductive.Graph: matchAny :: Graph gr => gr a b -> GDecomp gr a b
+ GHC.Data.Graph.Inductive.Graph: mkGraph :: Graph gr => [LNode a] -> [LEdge b] -> gr a b
+ GHC.Data.Graph.Inductive.Graph: mkUGraph :: Graph gr => [Node] -> [Edge] -> gr () ()
+ GHC.Data.Graph.Inductive.Graph: neighbors :: Graph gr => gr a b -> Node -> [Node]
+ GHC.Data.Graph.Inductive.Graph: neighbors' :: Context a b -> [Node]
+ GHC.Data.Graph.Inductive.Graph: nemap :: DynGraph gr => (a -> c) -> (b -> d) -> gr a b -> gr c d
+ GHC.Data.Graph.Inductive.Graph: newNodes :: Graph gr => Int -> gr a b -> [Node]
+ GHC.Data.Graph.Inductive.Graph: newtype LPath a
+ GHC.Data.Graph.Inductive.Graph: newtype OrdGr gr a b
+ GHC.Data.Graph.Inductive.Graph: nfilter :: DynGraph gr => (Node -> Bool) -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: nmap :: DynGraph gr => (a -> c) -> gr a b -> gr c b
+ GHC.Data.Graph.Inductive.Graph: noNodes :: Graph gr => gr a b -> Int
+ GHC.Data.Graph.Inductive.Graph: node' :: Context a b -> Node
+ GHC.Data.Graph.Inductive.Graph: nodeRange :: Graph gr => gr a b -> (Node, Node)
+ GHC.Data.Graph.Inductive.Graph: nodes :: Graph gr => gr a b -> [Node]
+ GHC.Data.Graph.Inductive.Graph: order :: Graph gr => gr a b -> Int
+ GHC.Data.Graph.Inductive.Graph: out :: Graph gr => gr a b -> Node -> [LEdge b]
+ GHC.Data.Graph.Inductive.Graph: out' :: Context a b -> [LEdge b]
+ GHC.Data.Graph.Inductive.Graph: outdeg :: Graph gr => gr a b -> Node -> Int
+ GHC.Data.Graph.Inductive.Graph: outdeg' :: Context a b -> Int
+ GHC.Data.Graph.Inductive.Graph: pre :: Graph gr => gr a b -> Node -> [Node]
+ GHC.Data.Graph.Inductive.Graph: pre' :: Context a b -> [Node]
+ GHC.Data.Graph.Inductive.Graph: prettify :: (DynGraph gr, Show a, Show b) => gr a b -> String
+ GHC.Data.Graph.Inductive.Graph: prettyPrint :: (DynGraph gr, Show a, Show b) => gr a b -> IO ()
+ GHC.Data.Graph.Inductive.Graph: size :: Graph gr => gr a b -> Int
+ GHC.Data.Graph.Inductive.Graph: subgraph :: DynGraph gr => [Node] -> gr a b -> gr a b
+ GHC.Data.Graph.Inductive.Graph: suc :: Graph gr => gr a b -> Node -> [Node]
+ GHC.Data.Graph.Inductive.Graph: suc' :: Context a b -> [Node]
+ GHC.Data.Graph.Inductive.Graph: toEdge :: LEdge b -> Edge
+ GHC.Data.Graph.Inductive.Graph: toLEdge :: Edge -> b -> LEdge b
+ GHC.Data.Graph.Inductive.Graph: type Adj b = [(b, Node)]
+ GHC.Data.Graph.Inductive.Graph: type Context a b = (Adj b, Node, a, Adj b)
+ GHC.Data.Graph.Inductive.Graph: type Decomp g a b = (MContext a b, g a b)
+ GHC.Data.Graph.Inductive.Graph: type Edge = (Node, Node)
+ GHC.Data.Graph.Inductive.Graph: type GDecomp g a b = (Context a b, g a b)
+ GHC.Data.Graph.Inductive.Graph: type LEdge b = (Node, Node, b)
+ GHC.Data.Graph.Inductive.Graph: type LNode a = (Node, a)
+ GHC.Data.Graph.Inductive.Graph: type MContext a b = Maybe (Context a b)
+ GHC.Data.Graph.Inductive.Graph: type Node = Int
+ GHC.Data.Graph.Inductive.Graph: type Path = [Node]
+ GHC.Data.Graph.Inductive.Graph: type UContext = ([Node], Node, [Node])
+ GHC.Data.Graph.Inductive.Graph: type UDecomp g = (Maybe UContext, g)
+ GHC.Data.Graph.Inductive.Graph: type UEdge = LEdge ()
+ GHC.Data.Graph.Inductive.Graph: type UNode = LNode ()
+ GHC.Data.Graph.Inductive.Graph: type UPath = [UNode]
+ GHC.Data.Graph.Inductive.Graph: ufold :: Graph gr => (Context a b -> c -> c) -> c -> gr a b -> c
+ GHC.Data.Graph.Inductive.PatriciaTree: data Gr a b
+ GHC.Data.Graph.Inductive.PatriciaTree: instance (GHC.Classes.Eq a, GHC.Classes.Ord b) => GHC.Classes.Eq (GHC.Data.Graph.Inductive.PatriciaTree.Gr a b)
+ GHC.Data.Graph.Inductive.PatriciaTree: instance (GHC.Read.Read a, GHC.Read.Read b) => GHC.Read.Read (GHC.Data.Graph.Inductive.PatriciaTree.Gr a b)
+ GHC.Data.Graph.Inductive.PatriciaTree: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (GHC.Data.Graph.Inductive.PatriciaTree.Gr a b)
+ GHC.Data.Graph.Inductive.PatriciaTree: instance Data.Bifunctor.Bifunctor GHC.Data.Graph.Inductive.PatriciaTree.Gr
+ GHC.Data.Graph.Inductive.PatriciaTree: instance GHC.Classes.Eq a => GHC.Classes.Eq (GHC.Data.Graph.Inductive.PatriciaTree.FromListCounting a)
+ GHC.Data.Graph.Inductive.PatriciaTree: instance GHC.Data.Graph.Inductive.Graph.DynGraph GHC.Data.Graph.Inductive.PatriciaTree.Gr
+ GHC.Data.Graph.Inductive.PatriciaTree: instance GHC.Data.Graph.Inductive.Graph.Graph GHC.Data.Graph.Inductive.PatriciaTree.Gr
+ GHC.Data.Graph.Inductive.PatriciaTree: instance GHC.Generics.Generic (GHC.Data.Graph.Inductive.PatriciaTree.Gr a b)
+ GHC.Data.Graph.Inductive.PatriciaTree: instance GHC.Read.Read a => GHC.Read.Read (GHC.Data.Graph.Inductive.PatriciaTree.FromListCounting a)
+ GHC.Data.Graph.Inductive.PatriciaTree: instance GHC.Show.Show a => GHC.Show.Show (GHC.Data.Graph.Inductive.PatriciaTree.FromListCounting a)
+ GHC.Data.Graph.Inductive.PatriciaTree: type UGr = Gr () ()
+ GHC.Driver.Config.StgToJS: initStgToJSConfig :: DynFlags -> StgToJSConfig
+ GHC.Driver.Pipeline: [T_Js] :: PipeEnv -> HscEnv -> Maybe ModLocation -> FilePath -> TPhase [Char]
+ GHC.Driver.Pipeline: jsPipeline :: P m => PipeEnv -> HscEnv -> Maybe ModLocation -> FilePath -> m FilePath
+ GHC.Driver.Pipeline.Execute: runJsPhase :: PipeEnv -> HscEnv -> FilePath -> IO FilePath
+ GHC.HsToCore.Foreign.JavaScript: dsJsFExport :: Id -> Coercion -> CLabelString -> CCallConv -> Bool -> DsM (CHeader, CStub, String, Int)
+ GHC.HsToCore.Foreign.JavaScript: dsJsFExportDynamic :: Id -> Coercion -> CCallConv -> DsM ([Binding], CHeader, CStub)
+ GHC.HsToCore.Foreign.JavaScript: dsJsImport :: Id -> Coercion -> CImportSpec -> CCallConv -> Safety -> Maybe Header -> DsM ([Binding], CHeader, CStub)
+ GHC.HsToCore.Monad: mkNamePprCtxDs :: DsM NamePprCtx
+ GHC.HsToCore.Types: [ds_name_ppr_ctx] :: DsGblEnv -> NamePprCtx
+ GHC.JS.Make: (.!) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.!=.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.!==.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.&&.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.<.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.<<.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.<=.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.==.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.===.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.>.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.>=.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.>>.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.>>>.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.^) :: JExpr -> FastString -> JExpr
+ GHC.JS.Make: (.|.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (.||.) :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: (|=) :: JExpr -> JExpr -> JStat
+ GHC.JS.Make: (||=) :: Ident -> JExpr -> JStat
+ GHC.JS.Make: allocClsA :: Int -> JExpr
+ GHC.JS.Make: allocData :: Int -> JExpr
+ GHC.JS.Make: app :: FastString -> [JExpr] -> JExpr
+ GHC.JS.Make: appS :: FastString -> [JExpr] -> JStat
+ GHC.JS.Make: assignAll :: [JExpr] -> [JExpr] -> JStat
+ GHC.JS.Make: assignAllEqual :: HasDebugCallStack => [JExpr] -> [JExpr] -> JStat
+ GHC.JS.Make: assignAllReverseOrder :: [JExpr] -> [JExpr] -> JStat
+ GHC.JS.Make: class ToJExpr a
+ GHC.JS.Make: class ToStat a
+ GHC.JS.Make: dataFieldName :: Int -> FastString
+ GHC.JS.Make: dataFieldNames :: [FastString]
+ GHC.JS.Make: decl :: Ident -> JStat
+ GHC.JS.Make: declAssignAll :: [Ident] -> [JExpr] -> JStat
+ GHC.JS.Make: false_ :: JExpr
+ GHC.JS.Make: if01 :: JExpr -> JExpr
+ GHC.JS.Make: if10 :: JExpr -> JExpr
+ GHC.JS.Make: ifBlockS :: JExpr -> [JStat] -> [JStat] -> JStat
+ GHC.JS.Make: ifS :: JExpr -> JStat -> JStat -> JStat
+ GHC.JS.Make: if_ :: JExpr -> JExpr -> JExpr -> JExpr
+ GHC.JS.Make: infixl 2 |=
+ GHC.JS.Make: infixl 6 .!==.
+ GHC.JS.Make: infixl 7 .<=.
+ GHC.JS.Make: infixl 8 .^
+ GHC.JS.Make: infixl 9 .>>>.
+ GHC.JS.Make: instance (GHC.JS.Make.ToJExpr a, GHC.JS.Make.ToJExpr b) => GHC.JS.Make.ToJExpr (a, b)
+ GHC.JS.Make: instance (GHC.JS.Make.ToJExpr a, GHC.JS.Make.ToJExpr b, GHC.JS.Make.ToJExpr c) => GHC.JS.Make.ToJExpr (a, b, c)
+ GHC.JS.Make: instance (GHC.JS.Make.ToJExpr a, GHC.JS.Make.ToJExpr b, GHC.JS.Make.ToJExpr c, GHC.JS.Make.ToJExpr d) => GHC.JS.Make.ToJExpr (a, b, c, d)
+ GHC.JS.Make: instance (GHC.JS.Make.ToJExpr a, GHC.JS.Make.ToJExpr b, GHC.JS.Make.ToJExpr c, GHC.JS.Make.ToJExpr d, GHC.JS.Make.ToJExpr e) => GHC.JS.Make.ToJExpr (a, b, c, d, e)
+ GHC.JS.Make: instance (GHC.JS.Make.ToJExpr a, GHC.JS.Make.ToJExpr b, GHC.JS.Make.ToJExpr c, GHC.JS.Make.ToJExpr d, GHC.JS.Make.ToJExpr e, GHC.JS.Make.ToJExpr f) => GHC.JS.Make.ToJExpr (a, b, c, d, e, f)
+ GHC.JS.Make: instance (GHC.JS.Make.ToSat a, b GHC.Types.~ GHC.JS.Syntax.JExpr) => GHC.JS.Make.ToSat (b -> a)
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr ()
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr GHC.Data.FastString.FastString
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr GHC.JS.Syntax.Ident
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr GHC.JS.Syntax.JExpr
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr GHC.JS.Syntax.JVal
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr GHC.Num.Integer.Integer
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr GHC.Types.Bool
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr GHC.Types.Char
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr GHC.Types.Double
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr GHC.Types.Int
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr a => GHC.JS.Make.ToJExpr (Data.Map.Internal.Map GHC.Base.String a)
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr a => GHC.JS.Make.ToJExpr (GHC.Types.Unique.Map.UniqMap GHC.Data.FastString.FastString a)
+ GHC.JS.Make: instance GHC.JS.Make.ToJExpr a => GHC.JS.Make.ToJExpr [a]
+ GHC.JS.Make: instance GHC.JS.Make.ToSat GHC.JS.Syntax.JExpr
+ GHC.JS.Make: instance GHC.JS.Make.ToSat GHC.JS.Syntax.JStat
+ GHC.JS.Make: instance GHC.JS.Make.ToSat [GHC.JS.Syntax.JExpr]
+ GHC.JS.Make: instance GHC.JS.Make.ToSat [GHC.JS.Syntax.JStat]
+ GHC.JS.Make: instance GHC.JS.Make.ToStat GHC.JS.Syntax.JExpr
+ GHC.JS.Make: instance GHC.JS.Make.ToStat GHC.JS.Syntax.JStat
+ GHC.JS.Make: instance GHC.JS.Make.ToStat [GHC.JS.Syntax.JExpr]
+ GHC.JS.Make: instance GHC.JS.Make.ToStat [GHC.JS.Syntax.JStat]
+ GHC.JS.Make: instance GHC.Num.Num GHC.JS.Syntax.JExpr
+ GHC.JS.Make: instance GHC.Real.Fractional GHC.JS.Syntax.JExpr
+ GHC.JS.Make: jFor :: (ToJExpr a, ToStat b) => JStat -> a -> JStat -> b -> JStat
+ GHC.JS.Make: jForEachIn :: ToSat a => JExpr -> (JExpr -> a) -> JStat
+ GHC.JS.Make: jForIn :: ToSat a => JExpr -> (JExpr -> a) -> JStat
+ GHC.JS.Make: jLam :: ToSat a => a -> JExpr
+ GHC.JS.Make: jString :: FastString -> JExpr
+ GHC.JS.Make: jTryCatchFinally :: ToSat a => JStat -> a -> JStat -> JStat
+ GHC.JS.Make: jVar :: ToSat a => a -> JStat
+ GHC.JS.Make: jhAdd :: (Ord k, ToJExpr a) => k -> a -> Map k JExpr -> Map k JExpr
+ GHC.JS.Make: jhEmpty :: Map k JExpr
+ GHC.JS.Make: jhFromList :: [(FastString, JExpr)] -> JVal
+ GHC.JS.Make: jhSingle :: (Ord k, ToJExpr a) => k -> a -> Map k JExpr
+ GHC.JS.Make: jwhenS :: JExpr -> JStat -> JStat
+ GHC.JS.Make: loop :: JExpr -> (JExpr -> JExpr) -> (JExpr -> JStat) -> JStat
+ GHC.JS.Make: loopBlockS :: JExpr -> (JExpr -> JExpr) -> (JExpr -> [JStat]) -> JStat
+ GHC.JS.Make: mask16 :: JExpr -> JExpr
+ GHC.JS.Make: mask8 :: JExpr -> JExpr
+ GHC.JS.Make: math_abs :: [JExpr] -> JExpr
+ GHC.JS.Make: math_acos :: [JExpr] -> JExpr
+ GHC.JS.Make: math_acosh :: [JExpr] -> JExpr
+ GHC.JS.Make: math_asin :: [JExpr] -> JExpr
+ GHC.JS.Make: math_asinh :: [JExpr] -> JExpr
+ GHC.JS.Make: math_atan :: [JExpr] -> JExpr
+ GHC.JS.Make: math_atanh :: [JExpr] -> JExpr
+ GHC.JS.Make: math_cos :: [JExpr] -> JExpr
+ GHC.JS.Make: math_cosh :: [JExpr] -> JExpr
+ GHC.JS.Make: math_exp :: [JExpr] -> JExpr
+ GHC.JS.Make: math_expm1 :: [JExpr] -> JExpr
+ GHC.JS.Make: math_fround :: [JExpr] -> JExpr
+ GHC.JS.Make: math_log :: [JExpr] -> JExpr
+ GHC.JS.Make: math_log1p :: [JExpr] -> JExpr
+ GHC.JS.Make: math_pow :: [JExpr] -> JExpr
+ GHC.JS.Make: math_sin :: [JExpr] -> JExpr
+ GHC.JS.Make: math_sinh :: [JExpr] -> JExpr
+ GHC.JS.Make: math_sqrt :: [JExpr] -> JExpr
+ GHC.JS.Make: math_tan :: [JExpr] -> JExpr
+ GHC.JS.Make: math_tanh :: [JExpr] -> JExpr
+ GHC.JS.Make: nullStat :: JStat
+ GHC.JS.Make: null_ :: JExpr
+ GHC.JS.Make: off16 :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: off32 :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: off64 :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: off8 :: JExpr -> JExpr -> JExpr
+ GHC.JS.Make: one_ :: JExpr
+ GHC.JS.Make: postDecrS :: JExpr -> JStat
+ GHC.JS.Make: postIncrS :: JExpr -> JStat
+ GHC.JS.Make: preDecrS :: JExpr -> JStat
+ GHC.JS.Make: preIncrS :: JExpr -> JStat
+ GHC.JS.Make: returnS :: JExpr -> JStat
+ GHC.JS.Make: returnStack :: JStat
+ GHC.JS.Make: signExtend16 :: JExpr -> JExpr
+ GHC.JS.Make: signExtend8 :: JExpr -> JExpr
+ GHC.JS.Make: three_ :: JExpr
+ GHC.JS.Make: toJExpr :: ToJExpr a => a -> JExpr
+ GHC.JS.Make: toJExprFromList :: ToJExpr a => [a] -> JExpr
+ GHC.JS.Make: toStat :: ToStat a => a -> JStat
+ GHC.JS.Make: trace :: ToJExpr a => a -> JStat
+ GHC.JS.Make: true_ :: JExpr
+ GHC.JS.Make: two_ :: JExpr
+ GHC.JS.Make: typeof :: JExpr -> JExpr
+ GHC.JS.Make: undefined_ :: JExpr
+ GHC.JS.Make: var :: FastString -> JExpr
+ GHC.JS.Make: zero_ :: JExpr
+ GHC.JS.Ppr: RenderJs :: !RenderJs -> JStat -> Doc -> !RenderJs -> JExpr -> Doc -> !RenderJs -> JVal -> Doc -> !RenderJs -> Ident -> Doc -> RenderJs
+ GHC.JS.Ppr: [renderJsE] :: RenderJs -> !RenderJs -> JExpr -> Doc
+ GHC.JS.Ppr: [renderJsI] :: RenderJs -> !RenderJs -> Ident -> Doc
+ GHC.JS.Ppr: [renderJsS] :: RenderJs -> !RenderJs -> JStat -> Doc
+ GHC.JS.Ppr: [renderJsV] :: RenderJs -> !RenderJs -> JVal -> Doc
+ GHC.JS.Ppr: braceNest :: Doc -> Doc
+ GHC.JS.Ppr: class JsToDoc a
+ GHC.JS.Ppr: data RenderJs
+ GHC.JS.Ppr: defaultRenderJs :: RenderJs
+ GHC.JS.Ppr: flattenBlocks :: [JStat] -> [JStat]
+ GHC.JS.Ppr: hangBrace :: Doc -> Doc -> Doc
+ GHC.JS.Ppr: instance GHC.JS.Ppr.JsToDoc GHC.JS.Syntax.Ident
+ GHC.JS.Ppr: instance GHC.JS.Ppr.JsToDoc GHC.JS.Syntax.JExpr
+ GHC.JS.Ppr: instance GHC.JS.Ppr.JsToDoc GHC.JS.Syntax.JStat
+ GHC.JS.Ppr: instance GHC.JS.Ppr.JsToDoc GHC.JS.Syntax.JVal
+ GHC.JS.Ppr: instance GHC.JS.Ppr.JsToDoc [GHC.JS.Syntax.JExpr]
+ GHC.JS.Ppr: instance GHC.JS.Ppr.JsToDoc [GHC.JS.Syntax.JStat]
+ GHC.JS.Ppr: instance GHC.Utils.Outputable.Outputable GHC.JS.Syntax.JExpr
+ GHC.JS.Ppr: instance GHC.Utils.Outputable.Outputable GHC.JS.Syntax.JVal
+ GHC.JS.Ppr: jsToDoc :: JsToDoc a => a -> Doc
+ GHC.JS.Ppr: jsToDocR :: JsToDoc a => RenderJs -> a -> Doc
+ GHC.JS.Ppr: pprStringLit :: FastString -> Doc
+ GHC.JS.Ppr: renderJs :: (JsToDoc a, JMacro a) => a -> Doc
+ GHC.JS.Ppr: renderJs' :: (JsToDoc a, JMacro a) => RenderJs -> a -> Doc
+ GHC.JS.Ppr: renderPrefixJs :: (JsToDoc a, JMacro a) => FastString -> a -> Doc
+ GHC.JS.Ppr: renderPrefixJs' :: (JsToDoc a, JMacro a) => RenderJs -> FastString -> a -> Doc
+ GHC.JS.Syntax: AddOp :: JOp
+ GHC.JS.Syntax: ApplExpr :: JExpr -> [JExpr] -> JExpr
+ GHC.JS.Syntax: ApplStat :: JExpr -> [JExpr] -> JStat
+ GHC.JS.Syntax: AssignStat :: JExpr -> JExpr -> JStat
+ GHC.JS.Syntax: BAndOp :: JOp
+ GHC.JS.Syntax: BNotOp :: JUOp
+ GHC.JS.Syntax: BOrOp :: JOp
+ GHC.JS.Syntax: BXorOp :: JOp
+ GHC.JS.Syntax: BlockStat :: [JStat] -> JStat
+ GHC.JS.Syntax: BreakStat :: Maybe JsLabel -> JStat
+ GHC.JS.Syntax: ContinueStat :: Maybe JsLabel -> JStat
+ GHC.JS.Syntax: DeclStat :: !Ident -> !Maybe JExpr -> JStat
+ GHC.JS.Syntax: DeleteOp :: JUOp
+ GHC.JS.Syntax: DivOp :: JOp
+ GHC.JS.Syntax: EqOp :: JOp
+ GHC.JS.Syntax: ForInStat :: Bool -> Ident -> JExpr -> JStat -> JStat
+ GHC.JS.Syntax: GeOp :: JOp
+ GHC.JS.Syntax: GtOp :: JOp
+ GHC.JS.Syntax: IS :: State [Ident] a -> IdentSupply a
+ GHC.JS.Syntax: IdxExpr :: JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: IfExpr :: JExpr -> JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: IfStat :: JExpr -> JStat -> JStat -> JStat
+ GHC.JS.Syntax: InOp :: JOp
+ GHC.JS.Syntax: InfixExpr :: JOp -> JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: InstanceofOp :: JOp
+ GHC.JS.Syntax: JDouble :: SaneDouble -> JVal
+ GHC.JS.Syntax: JFunc :: [Ident] -> JStat -> JVal
+ GHC.JS.Syntax: JHash :: UniqMap FastString JExpr -> JVal
+ GHC.JS.Syntax: JInt :: Integer -> JVal
+ GHC.JS.Syntax: JList :: [JExpr] -> JVal
+ GHC.JS.Syntax: JRegEx :: FastString -> JVal
+ GHC.JS.Syntax: JStr :: FastString -> JVal
+ GHC.JS.Syntax: JVar :: Ident -> JVal
+ GHC.JS.Syntax: LAndOp :: JOp
+ GHC.JS.Syntax: LOrOp :: JOp
+ GHC.JS.Syntax: LabelStat :: JsLabel -> JStat -> JStat
+ GHC.JS.Syntax: LeOp :: JOp
+ GHC.JS.Syntax: LeftShiftOp :: JOp
+ GHC.JS.Syntax: LtOp :: JOp
+ GHC.JS.Syntax: ModOp :: JOp
+ GHC.JS.Syntax: MulOp :: JOp
+ GHC.JS.Syntax: NegOp :: JUOp
+ GHC.JS.Syntax: NeqOp :: JOp
+ GHC.JS.Syntax: NewOp :: JUOp
+ GHC.JS.Syntax: NotOp :: JUOp
+ GHC.JS.Syntax: PlusOp :: JUOp
+ GHC.JS.Syntax: PostDecOp :: JUOp
+ GHC.JS.Syntax: PostIncOp :: JUOp
+ GHC.JS.Syntax: PreDecOp :: JUOp
+ GHC.JS.Syntax: PreIncOp :: JUOp
+ GHC.JS.Syntax: ReturnStat :: JExpr -> JStat
+ GHC.JS.Syntax: RightShiftOp :: JOp
+ GHC.JS.Syntax: SaneDouble :: Double -> SaneDouble
+ GHC.JS.Syntax: SelExpr :: JExpr -> Ident -> JExpr
+ GHC.JS.Syntax: StrictEqOp :: JOp
+ GHC.JS.Syntax: StrictNeqOp :: JOp
+ GHC.JS.Syntax: SubOp :: JOp
+ GHC.JS.Syntax: SwitchStat :: JExpr -> [(JExpr, JStat)] -> JStat -> JStat
+ GHC.JS.Syntax: TryStat :: JStat -> Ident -> JStat -> JStat -> JStat
+ GHC.JS.Syntax: TxtI :: FastString -> Ident
+ GHC.JS.Syntax: TypeofOp :: JUOp
+ GHC.JS.Syntax: UOpExpr :: JUOp -> JExpr -> JExpr
+ GHC.JS.Syntax: UOpStat :: JUOp -> JExpr -> JStat
+ GHC.JS.Syntax: UnsatBlock :: IdentSupply JStat -> JStat
+ GHC.JS.Syntax: UnsatExpr :: IdentSupply JExpr -> JExpr
+ GHC.JS.Syntax: UnsatVal :: IdentSupply JVal -> JVal
+ GHC.JS.Syntax: ValExpr :: JVal -> JExpr
+ GHC.JS.Syntax: VoidOp :: JUOp
+ GHC.JS.Syntax: WhileStat :: Bool -> JExpr -> JStat -> JStat
+ GHC.JS.Syntax: YieldOp :: JUOp
+ GHC.JS.Syntax: ZRightShiftOp :: JOp
+ GHC.JS.Syntax: [itxt] :: Ident -> FastString
+ GHC.JS.Syntax: [runIdentSupply] :: IdentSupply a -> State [Ident] a
+ GHC.JS.Syntax: [unSaneDouble] :: SaneDouble -> Double
+ GHC.JS.Syntax: data JExpr
+ GHC.JS.Syntax: data JOp
+ GHC.JS.Syntax: data JStat
+ GHC.JS.Syntax: data JUOp
+ GHC.JS.Syntax: data JVal
+ GHC.JS.Syntax: identFS :: Ident -> FastString
+ GHC.JS.Syntax: instance Control.DeepSeq.NFData (GHC.JS.Syntax.IdentSupply a)
+ GHC.JS.Syntax: instance Control.DeepSeq.NFData GHC.JS.Syntax.JOp
+ GHC.JS.Syntax: instance Control.DeepSeq.NFData GHC.JS.Syntax.JUOp
+ GHC.JS.Syntax: instance Control.DeepSeq.NFData GHC.JS.Syntax.SaneDouble
+ GHC.JS.Syntax: instance Data.Data.Data GHC.JS.Syntax.JOp
+ GHC.JS.Syntax: instance Data.Data.Data GHC.JS.Syntax.JUOp
+ GHC.JS.Syntax: instance Data.Data.Data GHC.JS.Syntax.SaneDouble
+ GHC.JS.Syntax: instance GHC.Base.Functor GHC.JS.Syntax.IdentSupply
+ GHC.JS.Syntax: instance GHC.Base.Monoid GHC.JS.Syntax.JStat
+ GHC.JS.Syntax: instance GHC.Base.Semigroup GHC.JS.Syntax.JStat
+ GHC.JS.Syntax: instance GHC.Classes.Eq GHC.JS.Syntax.Ident
+ GHC.JS.Syntax: instance GHC.Classes.Eq GHC.JS.Syntax.JExpr
+ GHC.JS.Syntax: instance GHC.Classes.Eq GHC.JS.Syntax.JOp
+ GHC.JS.Syntax: instance GHC.Classes.Eq GHC.JS.Syntax.JStat
+ GHC.JS.Syntax: instance GHC.Classes.Eq GHC.JS.Syntax.JUOp
+ GHC.JS.Syntax: instance GHC.Classes.Eq GHC.JS.Syntax.JVal
+ GHC.JS.Syntax: instance GHC.Classes.Eq GHC.JS.Syntax.SaneDouble
+ GHC.JS.Syntax: instance GHC.Classes.Eq a => GHC.Classes.Eq (GHC.JS.Syntax.IdentSupply a)
+ GHC.JS.Syntax: instance GHC.Classes.Ord GHC.JS.Syntax.JOp
+ GHC.JS.Syntax: instance GHC.Classes.Ord GHC.JS.Syntax.JUOp
+ GHC.JS.Syntax: instance GHC.Classes.Ord GHC.JS.Syntax.SaneDouble
+ GHC.JS.Syntax: instance GHC.Classes.Ord a => GHC.Classes.Ord (GHC.JS.Syntax.IdentSupply a)
+ GHC.JS.Syntax: instance GHC.Enum.Enum GHC.JS.Syntax.JOp
+ GHC.JS.Syntax: instance GHC.Enum.Enum GHC.JS.Syntax.JUOp
+ GHC.JS.Syntax: instance GHC.Generics.Generic GHC.JS.Syntax.JExpr
+ GHC.JS.Syntax: instance GHC.Generics.Generic GHC.JS.Syntax.JOp
+ GHC.JS.Syntax: instance GHC.Generics.Generic GHC.JS.Syntax.JStat
+ GHC.JS.Syntax: instance GHC.Generics.Generic GHC.JS.Syntax.JUOp
+ GHC.JS.Syntax: instance GHC.Generics.Generic GHC.JS.Syntax.JVal
+ GHC.JS.Syntax: instance GHC.Generics.Generic GHC.JS.Syntax.SaneDouble
+ GHC.JS.Syntax: instance GHC.Num.Num GHC.JS.Syntax.SaneDouble
+ GHC.JS.Syntax: instance GHC.Real.Fractional GHC.JS.Syntax.SaneDouble
+ GHC.JS.Syntax: instance GHC.Show.Show GHC.JS.Syntax.Ident
+ GHC.JS.Syntax: instance GHC.Show.Show GHC.JS.Syntax.JOp
+ GHC.JS.Syntax: instance GHC.Show.Show GHC.JS.Syntax.JUOp
+ GHC.JS.Syntax: instance GHC.Show.Show GHC.JS.Syntax.SaneDouble
+ GHC.JS.Syntax: instance GHC.Show.Show a => GHC.Show.Show (GHC.JS.Syntax.IdentSupply a)
+ GHC.JS.Syntax: instance GHC.Types.Unique.Uniquable GHC.JS.Syntax.Ident
+ GHC.JS.Syntax: newIdentSupply :: Maybe FastString -> [Ident]
+ GHC.JS.Syntax: newtype Ident
+ GHC.JS.Syntax: newtype IdentSupply a
+ GHC.JS.Syntax: newtype SaneDouble
+ GHC.JS.Syntax: pattern Add :: JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: pattern BAnd :: JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: pattern BNot :: JExpr -> JExpr
+ GHC.JS.Syntax: pattern BOr :: JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: pattern BXor :: JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: pattern Div :: JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: pattern Int :: Integer -> JExpr
+ GHC.JS.Syntax: pattern LAnd :: JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: pattern LOr :: JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: pattern Mod :: JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: pattern Mul :: JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: pattern Negate :: JExpr -> JExpr
+ GHC.JS.Syntax: pattern New :: JExpr -> JExpr
+ GHC.JS.Syntax: pattern Not :: JExpr -> JExpr
+ GHC.JS.Syntax: pattern PostDec :: JExpr -> JExpr
+ GHC.JS.Syntax: pattern PostInc :: JExpr -> JExpr
+ GHC.JS.Syntax: pattern PreDec :: JExpr -> JExpr
+ GHC.JS.Syntax: pattern PreInc :: JExpr -> JExpr
+ GHC.JS.Syntax: pattern String :: FastString -> JExpr
+ GHC.JS.Syntax: pattern Sub :: JExpr -> JExpr -> JExpr
+ GHC.JS.Syntax: pseudoSaturate :: IdentSupply a -> a
+ GHC.JS.Syntax: type JsLabel = LexicalFastString
+ GHC.JS.Transform: [JMGExpr] :: JExpr -> JMGadt JExpr
+ GHC.JS.Transform: [JMGId] :: Ident -> JMGadt Ident
+ GHC.JS.Transform: [JMGStat] :: JStat -> JMGadt JStat
+ GHC.JS.Transform: [JMGVal] :: JVal -> JMGadt JVal
+ GHC.JS.Transform: class Compos t
+ GHC.JS.Transform: class JMacro a
+ GHC.JS.Transform: compos :: Compos t => (forall a. a -> m a) -> (forall a b. m (a -> b) -> m a -> m b) -> (forall a. t a -> m (t a)) -> t c -> m (t c)
+ GHC.JS.Transform: composOp :: Compos t => (forall a. t a -> t a) -> t b -> t b
+ GHC.JS.Transform: composOpFold :: Compos t => b -> (b -> b -> b) -> (forall a. t a -> b) -> t c -> b
+ GHC.JS.Transform: composOpM :: (Compos t, Monad m) => (forall a. t a -> m (t a)) -> t b -> m (t b)
+ GHC.JS.Transform: composOpM_ :: (Compos t, Monad m) => (forall a. t a -> m ()) -> t b -> m ()
+ GHC.JS.Transform: data JMGadt a
+ GHC.JS.Transform: identsE :: JExpr -> [Ident]
+ GHC.JS.Transform: identsS :: JStat -> [Ident]
+ GHC.JS.Transform: identsV :: JVal -> [Ident]
+ GHC.JS.Transform: instance GHC.JS.Transform.Compos GHC.JS.Transform.JMGadt
+ GHC.JS.Transform: instance GHC.JS.Transform.JMacro GHC.JS.Syntax.Ident
+ GHC.JS.Transform: instance GHC.JS.Transform.JMacro GHC.JS.Syntax.JExpr
+ GHC.JS.Transform: instance GHC.JS.Transform.JMacro GHC.JS.Syntax.JStat
+ GHC.JS.Transform: instance GHC.JS.Transform.JMacro GHC.JS.Syntax.JVal
+ GHC.JS.Transform: jfromGADT :: JMacro a => JMGadt a -> a
+ GHC.JS.Transform: jsSaturate :: JMacro a => Maybe FastString -> a -> a
+ GHC.JS.Transform: jtoGADT :: JMacro a => a -> JMGadt a
+ GHC.JS.Transform: mapExprIdent :: (Ident -> JExpr) -> JExpr -> JExpr
+ GHC.JS.Transform: mapIdent :: (Ident -> JExpr) -> (JExpr -> JExpr, JStat -> JStat)
+ GHC.JS.Transform: mapStatIdent :: (Ident -> JExpr) -> JStat -> JStat
+ GHC.Plugins: FTF_C_C :: FunTyFlag
+ GHC.Plugins: FTF_C_T :: FunTyFlag
+ GHC.Plugins: FTF_T_C :: FunTyFlag
+ GHC.Plugins: FTF_T_T :: FunTyFlag
+ GHC.Plugins: SelArg :: FunSel
+ GHC.Plugins: SelForAll :: CoSel
+ GHC.Plugins: SelFun :: FunSel -> CoSel
+ GHC.Plugins: SelMult :: FunSel
+ GHC.Plugins: SelRes :: FunSel
+ GHC.Plugins: SelTyCon :: Int -> Role -> CoSel
+ GHC.Plugins: anonPiTyBinderType_maybe :: PiTyBinder -> Maybe Type
+ GHC.Plugins: appTyForAllTyFlags :: Type -> [Type] -> [ForAllTyFlag]
+ GHC.Plugins: binderFlag :: VarBndr tv argf -> argf
+ GHC.Plugins: binderFlags :: [VarBndr tv argf] -> [argf]
+ GHC.Plugins: chooseFunTyFlag :: HasDebugCallStack => Type -> Type -> FunTyFlag
+ GHC.Plugins: data CoSel
+ GHC.Plugins: data ForAllTyFlag
+ GHC.Plugins: data FunSel
+ GHC.Plugins: data FunTyFlag
+ GHC.Plugins: data PiTyBinder
+ GHC.Plugins: funRole :: Role -> FunSel -> Role
+ GHC.Plugins: funTyConAppTy_maybe :: FunTyFlag -> Type -> Type -> Type -> Maybe (TyCon, [Type])
+ GHC.Plugins: funTyFlagTyCon :: FunTyFlag -> TyCon
+ GHC.Plugins: getNthFromType :: HasDebugCallStack => CoSel -> Type -> Type
+ GHC.Plugins: getNthFun :: FunSel -> a -> a -> a -> a
+ GHC.Plugins: isAnonPiTyBinder :: PiTyBinder -> Bool
+ GHC.Plugins: isConstraintKind :: Kind -> Bool
+ GHC.Plugins: isConstraintLikeKind :: Kind -> Bool
+ GHC.Plugins: isInvisibleForAllTyFlag :: ForAllTyFlag -> Bool
+ GHC.Plugins: isInvisiblePiTyBinder :: PiTyBinder -> Bool
+ GHC.Plugins: isManyTy :: Mult -> Bool
+ GHC.Plugins: isNamedPiTyBinder :: PiTyBinder -> Bool
+ GHC.Plugins: isOneTy :: Mult -> Bool
+ GHC.Plugins: isTYPEorCONSTRAINT :: Kind -> Bool
+ GHC.Plugins: isTypeLikeKind :: Kind -> Bool
+ GHC.Plugins: isVisibleForAllTyFlag :: ForAllTyFlag -> Bool
+ GHC.Plugins: isVisiblePiTyBinder :: PiTyBinder -> Bool
+ GHC.Plugins: levityType_maybe :: LevityType -> Maybe Levity
+ GHC.Plugins: mkBoxedRepApp_maybe :: LevityType -> Maybe Type
+ GHC.Plugins: mkCONSTRAINTapp :: RuntimeRepType -> Type
+ GHC.Plugins: mkCONSTRAINTapp_maybe :: RuntimeRepType -> Maybe Type
+ GHC.Plugins: mkForAllTyBinder :: vis -> TyCoVar -> VarBndr TyCoVar vis
+ GHC.Plugins: mkForAllTyBinders :: vis -> [TyCoVar] -> [VarBndr TyCoVar vis]
+ GHC.Plugins: mkFunCo1 :: HasDebugCallStack => Role -> FunTyFlag -> CoercionN -> Coercion -> Coercion -> Coercion
+ GHC.Plugins: mkFunCo2 :: HasDebugCallStack => Role -> FunTyFlag -> FunTyFlag -> CoercionN -> Coercion -> Coercion -> Coercion
+ GHC.Plugins: mkFunCoNoFTF :: HasDebugCallStack => Role -> CoercionN -> Coercion -> Coercion -> Coercion
+ GHC.Plugins: mkFunctionType :: Mult -> Type -> Type -> Type
+ GHC.Plugins: mkInvisFunTys :: HasDebugCallStack => [Type] -> Type -> Type
+ GHC.Plugins: mkNakedFunCo1 :: Role -> FunTyFlag -> CoercionN -> Coercion -> Coercion -> Coercion
+ GHC.Plugins: mkNakedFunCo2 :: Role -> FunTyFlag -> FunTyFlag -> CoercionN -> Coercion -> Coercion -> Coercion
+ GHC.Plugins: mkRuntimeRepCo :: HasDebugCallStack => Coercion -> Coercion
+ GHC.Plugins: mkScaledFunTys :: HasDebugCallStack => [Scaled Type] -> Type -> Type
+ GHC.Plugins: mkScaledFunctionTys :: [Scaled Type] -> Type -> Type
+ GHC.Plugins: mkSelCo :: HasDebugCallStack => CoSel -> Coercion -> Coercion
+ GHC.Plugins: mkTYPEapp_maybe :: RuntimeRepType -> Maybe Type
+ GHC.Plugins: mkTupleRepApp_maybe :: Type -> Maybe Type
+ GHC.Plugins: namedPiTyBinder_maybe :: PiTyBinder -> Maybe TyCoVar
+ GHC.Plugins: pattern ManyTy :: Mult
+ GHC.Plugins: pattern OneTy :: Mult
+ GHC.Plugins: piTyBinderType :: PiTyBinder -> Type
+ GHC.Plugins: pprName :: IsLine doc => Name -> doc
+ GHC.Plugins: returnsConstraintKind :: Kind -> Bool
+ GHC.Plugins: sORTKind_maybe :: Kind -> Maybe (TypeOrConstraint, Type)
+ GHC.Plugins: splitAppTyNoView_maybe :: HasDebugCallStack => Type -> Maybe (Type, Type)
+ GHC.Plugins: splitAppTysNoView :: HasDebugCallStack => Type -> (Type, [Type])
+ GHC.Plugins: splitForAllForAllTyBinders :: Type -> ([ForAllTyBinder], Type)
+ GHC.Plugins: splitForAllInvisTyBinders :: Type -> ([InvisTyBinder], Type)
+ GHC.Plugins: splitForAllReqTyBinders :: Type -> ([ReqTyBinder], Type)
+ GHC.Plugins: splitRuntimeRep_maybe :: RuntimeRepType -> Maybe (TyCon, [Type])
+ GHC.Plugins: splitTyConAppNoView_maybe :: Type -> Maybe (TyCon, [Type])
+ GHC.Plugins: substTyVarToTyVar :: HasDebugCallStack => Subst -> TyVar -> TyVar
+ GHC.Plugins: tcMkInvisFunTy :: TypeOrConstraint -> Type -> Type -> Type
+ GHC.Plugins: tcMkScaledFunTys :: [Scaled Type] -> Type -> Type
+ GHC.Plugins: tcMkVisFunTy :: Mult -> Type -> Type -> Type
+ GHC.Plugins: tcSplitAppTyNoView_maybe :: Type -> Maybe (Type, Type)
+ GHC.Plugins: tcSplitTyConApp :: Type -> (TyCon, [Type])
+ GHC.Plugins: tidyForAllTyBinder :: TidyEnv -> VarBndr TyCoVar vis -> (TidyEnv, VarBndr TyCoVar vis)
+ GHC.Plugins: tidyForAllTyBinders :: TidyEnv -> [VarBndr TyCoVar vis] -> (TidyEnv, [VarBndr TyCoVar vis])
+ GHC.Plugins: tyConAppFunCo_maybe :: HasDebugCallStack => Role -> TyCon -> [Coercion] -> Maybe Coercion
+ GHC.Plugins: tyConAppFunTy_maybe :: HasDebugCallStack => TyCon -> [Type] -> Maybe Type
+ GHC.Plugins: tyConBindersPiTyBinders :: [TyConBinder] -> [PiTyBinder]
+ GHC.Plugins: tyConForAllTyFlags :: TyCon -> [Type] -> [ForAllTyFlag]
+ GHC.Plugins: tyConRole :: Role -> TyCon -> Int -> Role
+ GHC.Plugins: tyConRoleListRepresentational :: TyCon -> [Role]
+ GHC.Plugins: tyConRoleListX :: Role -> TyCon -> [Role]
+ GHC.Plugins: type ForAllTyBinder = VarBndr TyCoVar ForAllTyFlag
+ GHC.Plugins: type RuntimeRepType = Type
+ GHC.Plugins: typeOrConstraintKind :: TypeOrConstraint -> RuntimeRepType -> Kind
+ GHC.Plugins: typeTypeOrConstraint :: HasDebugCallStack => Type -> TypeOrConstraint
+ GHC.Rename.Expr: [UnexpectedStatement] :: forall body. Outputable (StmtLR GhcPs GhcPs body) => StmtLR GhcPs GhcPs body -> UnexpectedStatement
+ GHC.Rename.Expr: data UnexpectedStatement
+ GHC.StgToJS: stgToJS :: Logger -> StgToJSConfig -> [CgStgTopBinding] -> Module -> [SptEntry] -> ForeignStubs -> CollectedCCs -> FilePath -> IO ()
+ GHC.StgToJS.Apply: genApp :: HasDebugCallStack => ExprCtx -> Id -> [StgArg] -> G (JStat, ExprResult)
+ GHC.StgToJS.Apply: instance GHC.Classes.Eq GHC.StgToJS.Apply.ApplyConv
+ GHC.StgToJS.Apply: instance GHC.Classes.Eq GHC.StgToJS.Apply.ApplySpec
+ GHC.StgToJS.Apply: instance GHC.Classes.Ord GHC.StgToJS.Apply.ApplyConv
+ GHC.StgToJS.Apply: instance GHC.Classes.Ord GHC.StgToJS.Apply.ApplySpec
+ GHC.StgToJS.Apply: instance GHC.Show.Show GHC.StgToJS.Apply.ApplyConv
+ GHC.StgToJS.Apply: instance GHC.Show.Show GHC.StgToJS.Apply.ApplySpec
+ GHC.StgToJS.Apply: rtsApply :: StgToJSConfig -> JStat
+ GHC.StgToJS.Arg: allocConStatic :: HasDebugCallStack => Ident -> CostCentreStack -> DataCon -> [StgArg] -> G ()
+ GHC.StgToJS.Arg: allocUnboxedConStatic :: DataCon -> [StaticArg] -> StaticArg
+ GHC.StgToJS.Arg: allocateStaticList :: [StgArg] -> StgArg -> G StaticVal
+ GHC.StgToJS.Arg: genArg :: HasDebugCallStack => StgArg -> G [JExpr]
+ GHC.StgToJS.Arg: genIdArg :: HasDebugCallStack => Id -> G [JExpr]
+ GHC.StgToJS.Arg: genIdArgI :: HasDebugCallStack => Id -> G [Ident]
+ GHC.StgToJS.Arg: genIdStackArgI :: HasDebugCallStack => Id -> G [(Ident, StackSlot)]
+ GHC.StgToJS.Arg: jsStaticArg :: StaticArg -> JExpr
+ GHC.StgToJS.Arg: jsStaticArgs :: [StaticArg] -> JExpr
+ GHC.StgToJS.Closure: Closure :: JExpr -> JExpr -> JExpr -> JExpr -> Maybe JExpr -> Closure
+ GHC.StgToJS.Closure: CopyCC :: CopyCC
+ GHC.StgToJS.Closure: DontCopyCC :: CopyCC
+ GHC.StgToJS.Closure: [clCC] :: Closure -> Maybe JExpr
+ GHC.StgToJS.Closure: [clEntry] :: Closure -> JExpr
+ GHC.StgToJS.Closure: [clField1] :: Closure -> JExpr
+ GHC.StgToJS.Closure: [clField2] :: Closure -> JExpr
+ GHC.StgToJS.Closure: [clMeta] :: Closure -> JExpr
+ GHC.StgToJS.Closure: assignClosure :: JExpr -> Closure -> JStat
+ GHC.StgToJS.Closure: closure :: ClosureInfo -> JStat -> JStat
+ GHC.StgToJS.Closure: closureInfoStat :: Bool -> ClosureInfo -> JStat
+ GHC.StgToJS.Closure: conClosure :: Ident -> FastString -> CILayout -> Int -> JStat
+ GHC.StgToJS.Closure: copyClosure :: CopyCC -> JExpr -> JExpr -> JStat
+ GHC.StgToJS.Closure: data Closure
+ GHC.StgToJS.Closure: data CopyCC
+ GHC.StgToJS.Closure: newClosure :: Closure -> JExpr
+ GHC.StgToJS.CodeGen: stgToJS :: Logger -> StgToJSConfig -> [CgStgTopBinding] -> Module -> [SptEntry] -> ForeignStubs -> CollectedCCs -> FilePath -> IO ()
+ GHC.StgToJS.CoreUtils: NoSlot :: SlotCount
+ GHC.StgToJS.CoreUtils: OneSlot :: SlotCount
+ GHC.StgToJS.CoreUtils: TwoSlots :: SlotCount
+ GHC.StgToJS.CoreUtils: argVt :: StgArg -> VarType
+ GHC.StgToJS.CoreUtils: assocIdExprs :: Id -> [JExpr] -> [TypedExpr]
+ GHC.StgToJS.CoreUtils: assocIdPrimReps :: Outputable a => Id -> [a] -> [(PrimRep, [a])]
+ GHC.StgToJS.CoreUtils: assocPrimReps :: Outputable a => [PrimRep] -> [a] -> [(PrimRep, [a])]
+ GHC.StgToJS.CoreUtils: data SlotCount
+ GHC.StgToJS.CoreUtils: dataConType :: DataCon -> Type
+ GHC.StgToJS.CoreUtils: fixedLayout :: [VarType] -> CILayout
+ GHC.StgToJS.CoreUtils: idPrimReps :: Id -> [PrimRep]
+ GHC.StgToJS.CoreUtils: idVt :: HasDebugCallStack => Id -> [VarType]
+ GHC.StgToJS.CoreUtils: instance GHC.Classes.Eq GHC.StgToJS.CoreUtils.SlotCount
+ GHC.StgToJS.CoreUtils: instance GHC.Classes.Ord GHC.StgToJS.CoreUtils.SlotCount
+ GHC.StgToJS.CoreUtils: instance GHC.Show.Show GHC.StgToJS.CoreUtils.SlotCount
+ GHC.StgToJS.CoreUtils: instance GHC.Utils.Outputable.Outputable GHC.StgToJS.CoreUtils.SlotCount
+ GHC.StgToJS.CoreUtils: isBoolDataCon :: DataCon -> Bool
+ GHC.StgToJS.CoreUtils: isMatchable :: [VarType] -> Bool
+ GHC.StgToJS.CoreUtils: isMultiVar :: VarType -> Bool
+ GHC.StgToJS.CoreUtils: isPtr :: VarType -> Bool
+ GHC.StgToJS.CoreUtils: isSingleVar :: VarType -> Bool
+ GHC.StgToJS.CoreUtils: isUnboxable :: VarType -> Bool
+ GHC.StgToJS.CoreUtils: isUnboxableCon :: DataCon -> Bool
+ GHC.StgToJS.CoreUtils: isVoid :: VarType -> Bool
+ GHC.StgToJS.CoreUtils: kindPrimRep' :: HasDebugCallStack => SDoc -> Kind -> [PrimRep]
+ GHC.StgToJS.CoreUtils: might_be_a_function :: HasDebugCallStack => Type -> Bool
+ GHC.StgToJS.CoreUtils: mkArityTag :: Int -> Int -> Int
+ GHC.StgToJS.CoreUtils: primRepSize :: PrimRep -> SlotCount
+ GHC.StgToJS.CoreUtils: primRepVt :: HasDebugCallStack => PrimRep -> VarType
+ GHC.StgToJS.CoreUtils: primTypeVt :: HasDebugCallStack => Type -> VarType
+ GHC.StgToJS.CoreUtils: slotCount :: SlotCount -> Int
+ GHC.StgToJS.CoreUtils: stackSlotType :: Id -> VarType
+ GHC.StgToJS.CoreUtils: toTypeList :: [VarType] -> [Int]
+ GHC.StgToJS.CoreUtils: tyConPrimRep' :: HasDebugCallStack => TyCon -> [PrimRep]
+ GHC.StgToJS.CoreUtils: tyConVt :: HasDebugCallStack => TyCon -> [VarType]
+ GHC.StgToJS.CoreUtils: typePrimRep' :: HasDebugCallStack => UnaryType -> [PrimRep]
+ GHC.StgToJS.CoreUtils: typePrimReps :: Type -> [PrimRep]
+ GHC.StgToJS.CoreUtils: typeSize :: Type -> Int
+ GHC.StgToJS.CoreUtils: typeVt :: HasDebugCallStack => Type -> [VarType]
+ GHC.StgToJS.CoreUtils: uTypeVt :: HasDebugCallStack => UnaryType -> VarType
+ GHC.StgToJS.CoreUtils: varSize :: VarType -> Int
+ GHC.StgToJS.CoreUtils: varSlotCount :: VarType -> SlotCount
+ GHC.StgToJS.DataCon: allocCon :: Ident -> DataCon -> CostCentreStack -> [JExpr] -> G JStat
+ GHC.StgToJS.DataCon: allocDynamic :: StgToJSConfig -> Bool -> Ident -> JExpr -> [JExpr] -> Maybe JExpr -> JStat
+ GHC.StgToJS.DataCon: allocDynamicE :: Bool -> JExpr -> [JExpr] -> Maybe JExpr -> JExpr
+ GHC.StgToJS.DataCon: allocUnboxedCon :: DataCon -> [JExpr] -> JExpr
+ GHC.StgToJS.DataCon: genCon :: ExprCtx -> DataCon -> [JExpr] -> G JStat
+ GHC.StgToJS.Deps: genDependencyData :: HasDebugCallStack => Module -> [LinkableUnit] -> G Deps
+ GHC.StgToJS.Expr: genBody :: HasDebugCallStack => ExprCtx -> Id -> StgReg -> [Id] -> CgStgExpr -> G JStat
+ GHC.StgToJS.Expr: genEntryType :: HasDebugCallStack => [Id] -> G CIType
+ GHC.StgToJS.Expr: genExpr :: HasDebugCallStack => ExprCtx -> CgStgExpr -> G (JStat, ExprResult)
+ GHC.StgToJS.Expr: genStaticRefs :: LiveVars -> G CIStatic
+ GHC.StgToJS.Expr: genStaticRefsRhs :: CgStgRhs -> G CIStatic
+ GHC.StgToJS.Expr: instance GHC.Base.Functor GHC.StgToJS.Expr.Branch
+ GHC.StgToJS.Expr: instance GHC.Classes.Eq a => GHC.Classes.Eq (GHC.StgToJS.Expr.Branch a)
+ GHC.StgToJS.Expr: loadLiveFun :: [Id] -> G JStat
+ GHC.StgToJS.ExprCtx: ctxAssertEvaluated :: Id -> ExprCtx -> ExprCtx
+ GHC.StgToJS.ExprCtx: ctxClearLneFrame :: ExprCtx -> ExprCtx
+ GHC.StgToJS.ExprCtx: ctxEvaluatedIds :: ExprCtx -> UniqSet Id
+ GHC.StgToJS.ExprCtx: ctxIsEvaluated :: ExprCtx -> Id -> Bool
+ GHC.StgToJS.ExprCtx: ctxIsLneBinding :: ExprCtx -> Id -> Bool
+ GHC.StgToJS.ExprCtx: ctxIsLneLiveVar :: ExprCtx -> Id -> Bool
+ GHC.StgToJS.ExprCtx: ctxLneBindingStackSize :: ExprCtx -> Id -> Maybe Int
+ GHC.StgToJS.ExprCtx: ctxLneFrameSize :: ExprCtx -> Int
+ GHC.StgToJS.ExprCtx: ctxLneFrameVars :: ExprCtx -> [(Id, Int)]
+ GHC.StgToJS.ExprCtx: ctxLneShrinkStack :: ExprCtx -> Int -> ExprCtx
+ GHC.StgToJS.ExprCtx: ctxSetSrcSpan :: RealSrcSpan -> ExprCtx -> ExprCtx
+ GHC.StgToJS.ExprCtx: ctxSetTarget :: [TypedExpr] -> ExprCtx -> ExprCtx
+ GHC.StgToJS.ExprCtx: ctxSetTop :: Id -> ExprCtx -> ExprCtx
+ GHC.StgToJS.ExprCtx: ctxSrcSpan :: ExprCtx -> Maybe RealSrcSpan
+ GHC.StgToJS.ExprCtx: ctxTarget :: ExprCtx -> [TypedExpr]
+ GHC.StgToJS.ExprCtx: ctxUpdateLneFrame :: [(Id, Int)] -> [Id] -> ExprCtx -> ExprCtx
+ GHC.StgToJS.ExprCtx: data ExprCtx
+ GHC.StgToJS.ExprCtx: initExprCtx :: Id -> ExprCtx
+ GHC.StgToJS.FFI: genForeignCall :: HasDebugCallStack => ExprCtx -> ForeignCall -> Type -> [JExpr] -> [StgArg] -> G (JStat, ExprResult)
+ GHC.StgToJS.FFI: genPrimCall :: ExprCtx -> PrimCall -> [StgArg] -> Type -> G (JStat, ExprResult)
+ GHC.StgToJS.FFI: saturateFFI :: JMacro a => Int -> a -> a
+ GHC.StgToJS.Heap: closureCC :: JExpr -> JExpr
+ GHC.StgToJS.Heap: closureCC_ :: FastString
+ GHC.StgToJS.Heap: closureEntry :: JExpr -> JExpr
+ GHC.StgToJS.Heap: closureEntry_ :: FastString
+ GHC.StgToJS.Heap: closureField1 :: JExpr -> JExpr
+ GHC.StgToJS.Heap: closureField1_ :: FastString
+ GHC.StgToJS.Heap: closureField2 :: JExpr -> JExpr
+ GHC.StgToJS.Heap: closureField2_ :: FastString
+ GHC.StgToJS.Heap: closureMeta :: JExpr -> JExpr
+ GHC.StgToJS.Heap: closureMeta_ :: FastString
+ GHC.StgToJS.Heap: closureType :: JExpr -> JExpr
+ GHC.StgToJS.Heap: conTag :: JExpr -> JExpr
+ GHC.StgToJS.Heap: conTag' :: JExpr -> JExpr
+ GHC.StgToJS.Heap: entryClosureType :: JExpr -> JExpr
+ GHC.StgToJS.Heap: funArity :: JExpr -> JExpr
+ GHC.StgToJS.Heap: funArity' :: JExpr -> JExpr
+ GHC.StgToJS.Heap: funOrPapArity :: JExpr -> Maybe JExpr -> JExpr
+ GHC.StgToJS.Heap: isBlackhole :: JExpr -> JExpr
+ GHC.StgToJS.Heap: isCon :: JExpr -> JExpr
+ GHC.StgToJS.Heap: isCon' :: JExpr -> JExpr
+ GHC.StgToJS.Heap: isFun :: JExpr -> JExpr
+ GHC.StgToJS.Heap: isFun' :: JExpr -> JExpr
+ GHC.StgToJS.Heap: isObject :: JExpr -> JExpr
+ GHC.StgToJS.Heap: isPap :: JExpr -> JExpr
+ GHC.StgToJS.Heap: isPap' :: JExpr -> JExpr
+ GHC.StgToJS.Heap: isThunk :: JExpr -> JExpr
+ GHC.StgToJS.Heap: isThunk' :: JExpr -> JExpr
+ GHC.StgToJS.Heap: jTyObject :: JExpr
+ GHC.StgToJS.Heap: papArity :: JExpr -> JExpr
+ GHC.StgToJS.Ids: cachedIdentForId :: Id -> Maybe Int -> IdType -> G Ident
+ GHC.StgToJS.Ids: declVarsForId :: Id -> G JStat
+ GHC.StgToJS.Ids: freshIdent :: G Ident
+ GHC.StgToJS.Ids: freshUnique :: G Int
+ GHC.StgToJS.Ids: identForDataConEntryId :: Id -> G Ident
+ GHC.StgToJS.Ids: identForDataConWorker :: DataCon -> G Ident
+ GHC.StgToJS.Ids: identForEntryId :: Id -> G Ident
+ GHC.StgToJS.Ids: identForId :: Id -> G Ident
+ GHC.StgToJS.Ids: identForIdN :: Id -> Int -> G Ident
+ GHC.StgToJS.Ids: identsForId :: Id -> G [Ident]
+ GHC.StgToJS.Ids: makeIdentForId :: Id -> Maybe Int -> IdType -> Module -> Ident
+ GHC.StgToJS.Ids: varForDataConEntryId :: Id -> G JExpr
+ GHC.StgToJS.Ids: varForDataConWorker :: DataCon -> G JExpr
+ GHC.StgToJS.Ids: varForEntryId :: Id -> G JExpr
+ GHC.StgToJS.Ids: varForId :: Id -> G JExpr
+ GHC.StgToJS.Ids: varForIdN :: Id -> Int -> G JExpr
+ GHC.StgToJS.Ids: varsForId :: Id -> G [JExpr]
+ GHC.StgToJS.Linker.Linker: embedJsFile :: Logger -> DynFlags -> TmpFs -> UnitEnv -> FilePath -> FilePath -> IO ()
+ GHC.StgToJS.Linker.Linker: jsLinkBinary :: JSLinkConfig -> StgToJSConfig -> [FilePath] -> Logger -> DynFlags -> UnitEnv -> [FilePath] -> [UnitId] -> IO ()
+ GHC.StgToJS.Linker.Types: GhcjsEnv :: MVar (Map (Set FilePath) (Map Module (Deps, DepsLocation), [LinkableUnit])) -> GhcjsEnv
+ GHC.StgToJS.Linker.Types: JSLinkConfig :: Bool -> Bool -> Bool -> Bool -> Bool -> JSLinkConfig
+ GHC.StgToJS.Linker.Types: ObjFile :: FilePath -> LinkedObj
+ GHC.StgToJS.Linker.Types: ObjLoaded :: String -> Object -> LinkedObj
+ GHC.StgToJS.Linker.Types: [lcNoHsMain] :: JSLinkConfig -> Bool
+ GHC.StgToJS.Linker.Types: [lcNoJSExecutables] :: JSLinkConfig -> Bool
+ GHC.StgToJS.Linker.Types: [lcNoRts] :: JSLinkConfig -> Bool
+ GHC.StgToJS.Linker.Types: [lcNoStats] :: JSLinkConfig -> Bool
+ GHC.StgToJS.Linker.Types: [lcOnlyOut] :: JSLinkConfig -> Bool
+ GHC.StgToJS.Linker.Types: [linkerArchiveDeps] :: GhcjsEnv -> MVar (Map (Set FilePath) (Map Module (Deps, DepsLocation), [LinkableUnit]))
+ GHC.StgToJS.Linker.Types: data GhcjsEnv
+ GHC.StgToJS.Linker.Types: data JSLinkConfig
+ GHC.StgToJS.Linker.Types: data LinkedObj
+ GHC.StgToJS.Linker.Types: defaultJSLinkConfig :: JSLinkConfig
+ GHC.StgToJS.Linker.Types: generateAllJs :: JSLinkConfig -> Bool
+ GHC.StgToJS.Linker.Types: instance GHC.Utils.Outputable.Outputable GHC.StgToJS.Linker.Types.LinkedObj
+ GHC.StgToJS.Linker.Types: newGhcjsEnv :: IO GhcjsEnv
+ GHC.StgToJS.Linker.Types: type LinkableUnit = (Module, Int)
+ GHC.StgToJS.Linker.Utils: CPP :: JSOption
+ GHC.StgToJS.Linker.Utils: commonCppDefs :: Bool -> ByteString
+ GHC.StgToJS.Linker.Utils: data JSOption
+ GHC.StgToJS.Linker.Utils: getInstalledPackageHsLibs :: UnitState -> UnitId -> [ShortText]
+ GHC.StgToJS.Linker.Utils: getInstalledPackageLibDirs :: UnitState -> UnitId -> [ShortText]
+ GHC.StgToJS.Linker.Utils: getOptionsFromJsFile :: FilePath -> IO [JSOption]
+ GHC.StgToJS.Linker.Utils: instance GHC.Classes.Eq GHC.StgToJS.Linker.Utils.JSOption
+ GHC.StgToJS.Linker.Utils: instance GHC.Classes.Ord GHC.StgToJS.Linker.Utils.JSOption
+ GHC.StgToJS.Linker.Utils: jsExeFileName :: DynFlags -> FilePath
+ GHC.StgToJS.Literal: genLit :: HasDebugCallStack => Literal -> G [JExpr]
+ GHC.StgToJS.Literal: genStaticLit :: Literal -> G [StaticLit]
+ GHC.StgToJS.Monad: GlobalOcc :: !Ident -> !Id -> !Word -> GlobalOcc
+ GHC.StgToJS.Monad: [global_count] :: GlobalOcc -> !Word
+ GHC.StgToJS.Monad: [global_id] :: GlobalOcc -> !Id
+ GHC.StgToJS.Monad: [global_ident] :: GlobalOcc -> !Ident
+ GHC.StgToJS.Monad: addDependency :: OtherSymb -> G ()
+ GHC.StgToJS.Monad: assertRtsStat :: G JStat -> G JStat
+ GHC.StgToJS.Monad: data GlobalOcc
+ GHC.StgToJS.Monad: emitClosureInfo :: ClosureInfo -> G ()
+ GHC.StgToJS.Monad: emitForeign :: Maybe RealSrcSpan -> FastString -> Safety -> CCallConv -> [FastString] -> FastString -> G ()
+ GHC.StgToJS.Monad: emitGlobal :: JStat -> G ()
+ GHC.StgToJS.Monad: emitStatic :: FastString -> StaticVal -> Maybe Ident -> G ()
+ GHC.StgToJS.Monad: emitToplevel :: JStat -> G ()
+ GHC.StgToJS.Monad: getGlobalIdCache :: G GlobalIdCache
+ GHC.StgToJS.Monad: getSettings :: G StgToJSConfig
+ GHC.StgToJS.Monad: globalOccs :: JStat -> G [GlobalOcc]
+ GHC.StgToJS.Monad: modifyGroup :: (GenGroupState -> GenGroupState) -> G ()
+ GHC.StgToJS.Monad: resetGroup :: G ()
+ GHC.StgToJS.Monad: runG :: StgToJSConfig -> Module -> UniqFM Id CgStgExpr -> G a -> IO a
+ GHC.StgToJS.Monad: setGlobalIdCache :: GlobalIdCache -> G ()
+ GHC.StgToJS.Object: ArchiveFile :: FilePath -> DepsLocation
+ GHC.StgToJS.Object: BlockDeps :: [Int] -> [ExportedFun] -> BlockDeps
+ GHC.StgToJS.Object: Deps :: !Module -> !BlockIds -> !Map ExportedFun BlockId -> !Array BlockId BlockDeps -> Deps
+ GHC.StgToJS.Object: ExportedFun :: !Module -> !LexicalFastString -> ExportedFun
+ GHC.StgToJS.Object: InMemory :: String -> Object -> DepsLocation
+ GHC.StgToJS.Object: IndexEntry :: ![FastString] -> !Bin ObjUnit -> IndexEntry
+ GHC.StgToJS.Object: Object :: !ModuleName -> !BinHandle -> !Bin ObjUnit -> !Deps -> !Index -> Object
+ GHC.StgToJS.Object: ObjectFile :: FilePath -> DepsLocation
+ GHC.StgToJS.Object: [blockBlockDeps] :: BlockDeps -> [Int]
+ GHC.StgToJS.Object: [blockFunDeps] :: BlockDeps -> [ExportedFun]
+ GHC.StgToJS.Object: [depsBlocks] :: Deps -> !Array BlockId BlockDeps
+ GHC.StgToJS.Object: [depsHaskellExported] :: Deps -> !Map ExportedFun BlockId
+ GHC.StgToJS.Object: [depsModule] :: Deps -> !Module
+ GHC.StgToJS.Object: [depsRequired] :: Deps -> !BlockIds
+ GHC.StgToJS.Object: [funModule] :: ExportedFun -> !Module
+ GHC.StgToJS.Object: [funSymbol] :: ExportedFun -> !LexicalFastString
+ GHC.StgToJS.Object: [idxOffset] :: IndexEntry -> !Bin ObjUnit
+ GHC.StgToJS.Object: [idxSymbols] :: IndexEntry -> ![FastString]
+ GHC.StgToJS.Object: [objDeps] :: Object -> !Deps
+ GHC.StgToJS.Object: [objHandle] :: Object -> !BinHandle
+ GHC.StgToJS.Object: [objIndex] :: Object -> !Index
+ GHC.StgToJS.Object: [objModuleName] :: Object -> !ModuleName
+ GHC.StgToJS.Object: [objPayloadOffset] :: Object -> !Bin ObjUnit
+ GHC.StgToJS.Object: data BlockDeps
+ GHC.StgToJS.Object: data Deps
+ GHC.StgToJS.Object: data DepsLocation
+ GHC.StgToJS.Object: data ExportedFun
+ GHC.StgToJS.Object: data IndexEntry
+ GHC.StgToJS.Object: data Object
+ GHC.StgToJS.Object: getObject :: BinHandle -> IO (Maybe Object)
+ GHC.StgToJS.Object: getObjectBody :: BinHandle -> ModuleName -> IO Object
+ GHC.StgToJS.Object: getObjectHeader :: BinHandle -> IO (Either String ModuleName)
+ GHC.StgToJS.Object: getObjectUnits :: Object -> (Word -> IndexEntry -> Bool) -> IO [ObjUnit]
+ GHC.StgToJS.Object: instance GHC.Classes.Eq GHC.StgToJS.Object.ExportedFun
+ GHC.StgToJS.Object: instance GHC.Classes.Ord GHC.StgToJS.Object.ExportedFun
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.JS.Syntax.Ident
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.JS.Syntax.JExpr
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.JS.Syntax.JOp
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.JS.Syntax.JStat
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.JS.Syntax.JUOp
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.JS.Syntax.JVal
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.JS.Syntax.SaneDouble
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Object.BlockDeps
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Object.Deps
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Object.ExportedFun
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Object.IndexEntry
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.CILayout
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.CIRegs
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.CIStatic
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.CIType
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.ClosureInfo
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.ExpFun
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.ForeignJSRef
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.JSFFIType
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.StaticArg
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.StaticInfo
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.StaticLit
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.StaticUnboxed
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.StaticVal
+ GHC.StgToJS.Object: instance GHC.Utils.Binary.Binary GHC.StgToJS.Types.VarType
+ GHC.StgToJS.Object: instance GHC.Utils.Outputable.Outputable GHC.StgToJS.Object.Deps
+ GHC.StgToJS.Object: instance GHC.Utils.Outputable.Outputable GHC.StgToJS.Object.DepsLocation
+ GHC.StgToJS.Object: instance GHC.Utils.Outputable.Outputable GHC.StgToJS.Object.ExportedFun
+ GHC.StgToJS.Object: isGlobalUnit :: Int -> Bool
+ GHC.StgToJS.Object: isJsObjectFile :: FilePath -> IO Bool
+ GHC.StgToJS.Object: putObject :: BinHandle -> ModuleName -> Deps -> [ObjUnit] -> IO ()
+ GHC.StgToJS.Object: readObject :: FilePath -> IO (Maybe Object)
+ GHC.StgToJS.Object: readObjectDeps :: FilePath -> IO (Maybe Deps)
+ GHC.StgToJS.Object: readObjectUnits :: FilePath -> (Word -> IndexEntry -> Bool) -> IO [ObjUnit]
+ GHC.StgToJS.Prim: genPrim :: Bool -> Bool -> Type -> PrimOp -> [JExpr] -> [JExpr] -> PrimRes
+ GHC.StgToJS.Printer: ghcjsRenderJs :: RenderJs
+ GHC.StgToJS.Printer: pretty :: JStat -> Doc
+ GHC.StgToJS.Printer: prettyBlock :: RenderJs -> [JStat] -> Doc
+ GHC.StgToJS.Profiling: ccsVarJ :: CostCentreStack -> G (Maybe JExpr)
+ GHC.StgToJS.Profiling: costCentreLbl :: CostCentre -> G Ident
+ GHC.StgToJS.Profiling: costCentreStackLbl :: CostCentreStack -> G (Maybe Ident)
+ GHC.StgToJS.Profiling: emitCostCentreDecl :: CostCentre -> G ()
+ GHC.StgToJS.Profiling: emitCostCentreStackDecl :: CostCentreStack -> G ()
+ GHC.StgToJS.Profiling: enterCostCentreFun :: CostCentreStack -> JStat
+ GHC.StgToJS.Profiling: enterCostCentreThunk :: JStat
+ GHC.StgToJS.Profiling: ifProfiling :: Monoid m => m -> G m
+ GHC.StgToJS.Profiling: ifProfilingM :: Monoid m => G m -> G m
+ GHC.StgToJS.Profiling: initCostCentres :: CollectedCCs -> G ()
+ GHC.StgToJS.Profiling: jCafCCS :: JExpr
+ GHC.StgToJS.Profiling: jCurrentCCS :: JExpr
+ GHC.StgToJS.Profiling: jSystemCCS :: JExpr
+ GHC.StgToJS.Profiling: profStat :: StgToJSConfig -> JStat -> JStat
+ GHC.StgToJS.Profiling: profiling :: G Bool
+ GHC.StgToJS.Profiling: pushRestoreCCS :: JStat
+ GHC.StgToJS.Profiling: setCC :: CostCentre -> Bool -> Bool -> G JStat
+ GHC.StgToJS.Profiling: singletonCCSLbl :: CostCentre -> G Ident
+ GHC.StgToJS.Regs: R1 :: StgReg
+ GHC.StgToJS.Regs: R10 :: StgReg
+ GHC.StgToJS.Regs: R100 :: StgReg
+ GHC.StgToJS.Regs: R101 :: StgReg
+ GHC.StgToJS.Regs: R102 :: StgReg
+ GHC.StgToJS.Regs: R103 :: StgReg
+ GHC.StgToJS.Regs: R104 :: StgReg
+ GHC.StgToJS.Regs: R105 :: StgReg
+ GHC.StgToJS.Regs: R106 :: StgReg
+ GHC.StgToJS.Regs: R107 :: StgReg
+ GHC.StgToJS.Regs: R108 :: StgReg
+ GHC.StgToJS.Regs: R109 :: StgReg
+ GHC.StgToJS.Regs: R11 :: StgReg
+ GHC.StgToJS.Regs: R110 :: StgReg
+ GHC.StgToJS.Regs: R111 :: StgReg
+ GHC.StgToJS.Regs: R112 :: StgReg
+ GHC.StgToJS.Regs: R113 :: StgReg
+ GHC.StgToJS.Regs: R114 :: StgReg
+ GHC.StgToJS.Regs: R115 :: StgReg
+ GHC.StgToJS.Regs: R116 :: StgReg
+ GHC.StgToJS.Regs: R117 :: StgReg
+ GHC.StgToJS.Regs: R118 :: StgReg
+ GHC.StgToJS.Regs: R119 :: StgReg
+ GHC.StgToJS.Regs: R12 :: StgReg
+ GHC.StgToJS.Regs: R120 :: StgReg
+ GHC.StgToJS.Regs: R121 :: StgReg
+ GHC.StgToJS.Regs: R122 :: StgReg
+ GHC.StgToJS.Regs: R123 :: StgReg
+ GHC.StgToJS.Regs: R124 :: StgReg
+ GHC.StgToJS.Regs: R125 :: StgReg
+ GHC.StgToJS.Regs: R126 :: StgReg
+ GHC.StgToJS.Regs: R127 :: StgReg
+ GHC.StgToJS.Regs: R128 :: StgReg
+ GHC.StgToJS.Regs: R13 :: StgReg
+ GHC.StgToJS.Regs: R14 :: StgReg
+ GHC.StgToJS.Regs: R15 :: StgReg
+ GHC.StgToJS.Regs: R16 :: StgReg
+ GHC.StgToJS.Regs: R17 :: StgReg
+ GHC.StgToJS.Regs: R18 :: StgReg
+ GHC.StgToJS.Regs: R19 :: StgReg
+ GHC.StgToJS.Regs: R2 :: StgReg
+ GHC.StgToJS.Regs: R20 :: StgReg
+ GHC.StgToJS.Regs: R21 :: StgReg
+ GHC.StgToJS.Regs: R22 :: StgReg
+ GHC.StgToJS.Regs: R23 :: StgReg
+ GHC.StgToJS.Regs: R24 :: StgReg
+ GHC.StgToJS.Regs: R25 :: StgReg
+ GHC.StgToJS.Regs: R26 :: StgReg
+ GHC.StgToJS.Regs: R27 :: StgReg
+ GHC.StgToJS.Regs: R28 :: StgReg
+ GHC.StgToJS.Regs: R29 :: StgReg
+ GHC.StgToJS.Regs: R3 :: StgReg
+ GHC.StgToJS.Regs: R30 :: StgReg
+ GHC.StgToJS.Regs: R31 :: StgReg
+ GHC.StgToJS.Regs: R32 :: StgReg
+ GHC.StgToJS.Regs: R33 :: StgReg
+ GHC.StgToJS.Regs: R34 :: StgReg
+ GHC.StgToJS.Regs: R35 :: StgReg
+ GHC.StgToJS.Regs: R36 :: StgReg
+ GHC.StgToJS.Regs: R37 :: StgReg
+ GHC.StgToJS.Regs: R38 :: StgReg
+ GHC.StgToJS.Regs: R39 :: StgReg
+ GHC.StgToJS.Regs: R4 :: StgReg
+ GHC.StgToJS.Regs: R40 :: StgReg
+ GHC.StgToJS.Regs: R41 :: StgReg
+ GHC.StgToJS.Regs: R42 :: StgReg
+ GHC.StgToJS.Regs: R43 :: StgReg
+ GHC.StgToJS.Regs: R44 :: StgReg
+ GHC.StgToJS.Regs: R45 :: StgReg
+ GHC.StgToJS.Regs: R46 :: StgReg
+ GHC.StgToJS.Regs: R47 :: StgReg
+ GHC.StgToJS.Regs: R48 :: StgReg
+ GHC.StgToJS.Regs: R49 :: StgReg
+ GHC.StgToJS.Regs: R5 :: StgReg
+ GHC.StgToJS.Regs: R50 :: StgReg
+ GHC.StgToJS.Regs: R51 :: StgReg
+ GHC.StgToJS.Regs: R52 :: StgReg
+ GHC.StgToJS.Regs: R53 :: StgReg
+ GHC.StgToJS.Regs: R54 :: StgReg
+ GHC.StgToJS.Regs: R55 :: StgReg
+ GHC.StgToJS.Regs: R56 :: StgReg
+ GHC.StgToJS.Regs: R57 :: StgReg
+ GHC.StgToJS.Regs: R58 :: StgReg
+ GHC.StgToJS.Regs: R59 :: StgReg
+ GHC.StgToJS.Regs: R6 :: StgReg
+ GHC.StgToJS.Regs: R60 :: StgReg
+ GHC.StgToJS.Regs: R61 :: StgReg
+ GHC.StgToJS.Regs: R62 :: StgReg
+ GHC.StgToJS.Regs: R63 :: StgReg
+ GHC.StgToJS.Regs: R64 :: StgReg
+ GHC.StgToJS.Regs: R65 :: StgReg
+ GHC.StgToJS.Regs: R66 :: StgReg
+ GHC.StgToJS.Regs: R67 :: StgReg
+ GHC.StgToJS.Regs: R68 :: StgReg
+ GHC.StgToJS.Regs: R69 :: StgReg
+ GHC.StgToJS.Regs: R7 :: StgReg
+ GHC.StgToJS.Regs: R70 :: StgReg
+ GHC.StgToJS.Regs: R71 :: StgReg
+ GHC.StgToJS.Regs: R72 :: StgReg
+ GHC.StgToJS.Regs: R73 :: StgReg
+ GHC.StgToJS.Regs: R74 :: StgReg
+ GHC.StgToJS.Regs: R75 :: StgReg
+ GHC.StgToJS.Regs: R76 :: StgReg
+ GHC.StgToJS.Regs: R77 :: StgReg
+ GHC.StgToJS.Regs: R78 :: StgReg
+ GHC.StgToJS.Regs: R79 :: StgReg
+ GHC.StgToJS.Regs: R8 :: StgReg
+ GHC.StgToJS.Regs: R80 :: StgReg
+ GHC.StgToJS.Regs: R81 :: StgReg
+ GHC.StgToJS.Regs: R82 :: StgReg
+ GHC.StgToJS.Regs: R83 :: StgReg
+ GHC.StgToJS.Regs: R84 :: StgReg
+ GHC.StgToJS.Regs: R85 :: StgReg
+ GHC.StgToJS.Regs: R86 :: StgReg
+ GHC.StgToJS.Regs: R87 :: StgReg
+ GHC.StgToJS.Regs: R88 :: StgReg
+ GHC.StgToJS.Regs: R89 :: StgReg
+ GHC.StgToJS.Regs: R9 :: StgReg
+ GHC.StgToJS.Regs: R90 :: StgReg
+ GHC.StgToJS.Regs: R91 :: StgReg
+ GHC.StgToJS.Regs: R92 :: StgReg
+ GHC.StgToJS.Regs: R93 :: StgReg
+ GHC.StgToJS.Regs: R94 :: StgReg
+ GHC.StgToJS.Regs: R95 :: StgReg
+ GHC.StgToJS.Regs: R96 :: StgReg
+ GHC.StgToJS.Regs: R97 :: StgReg
+ GHC.StgToJS.Regs: R98 :: StgReg
+ GHC.StgToJS.Regs: R99 :: StgReg
+ GHC.StgToJS.Regs: Ret1 :: StgRet
+ GHC.StgToJS.Regs: Ret10 :: StgRet
+ GHC.StgToJS.Regs: Ret2 :: StgRet
+ GHC.StgToJS.Regs: Ret3 :: StgRet
+ GHC.StgToJS.Regs: Ret4 :: StgRet
+ GHC.StgToJS.Regs: Ret5 :: StgRet
+ GHC.StgToJS.Regs: Ret6 :: StgRet
+ GHC.StgToJS.Regs: Ret7 :: StgRet
+ GHC.StgToJS.Regs: Ret8 :: StgRet
+ GHC.StgToJS.Regs: Ret9 :: StgRet
+ GHC.StgToJS.Regs: Sp :: Special
+ GHC.StgToJS.Regs: Stack :: Special
+ GHC.StgToJS.Regs: data Special
+ GHC.StgToJS.Regs: data StgReg
+ GHC.StgToJS.Regs: data StgRet
+ GHC.StgToJS.Regs: instance GHC.Classes.Eq GHC.StgToJS.Regs.Special
+ GHC.StgToJS.Regs: instance GHC.Classes.Eq GHC.StgToJS.Regs.StgReg
+ GHC.StgToJS.Regs: instance GHC.Classes.Eq GHC.StgToJS.Regs.StgRet
+ GHC.StgToJS.Regs: instance GHC.Classes.Ord GHC.StgToJS.Regs.StgReg
+ GHC.StgToJS.Regs: instance GHC.Classes.Ord GHC.StgToJS.Regs.StgRet
+ GHC.StgToJS.Regs: instance GHC.Enum.Bounded GHC.StgToJS.Regs.StgReg
+ GHC.StgToJS.Regs: instance GHC.Enum.Bounded GHC.StgToJS.Regs.StgRet
+ GHC.StgToJS.Regs: instance GHC.Enum.Enum GHC.StgToJS.Regs.StgReg
+ GHC.StgToJS.Regs: instance GHC.Enum.Enum GHC.StgToJS.Regs.StgRet
+ GHC.StgToJS.Regs: instance GHC.Ix.Ix GHC.StgToJS.Regs.StgReg
+ GHC.StgToJS.Regs: instance GHC.Ix.Ix GHC.StgToJS.Regs.StgRet
+ GHC.StgToJS.Regs: instance GHC.JS.Make.ToJExpr GHC.StgToJS.Regs.Special
+ GHC.StgToJS.Regs: instance GHC.JS.Make.ToJExpr GHC.StgToJS.Regs.StgReg
+ GHC.StgToJS.Regs: instance GHC.JS.Make.ToJExpr GHC.StgToJS.Regs.StgRet
+ GHC.StgToJS.Regs: instance GHC.Show.Show GHC.StgToJS.Regs.Special
+ GHC.StgToJS.Regs: instance GHC.Show.Show GHC.StgToJS.Regs.StgReg
+ GHC.StgToJS.Regs: instance GHC.Show.Show GHC.StgToJS.Regs.StgRet
+ GHC.StgToJS.Regs: intToJSReg :: Int -> StgReg
+ GHC.StgToJS.Regs: jsReg :: Int -> JExpr
+ GHC.StgToJS.Regs: jsRegToInt :: StgReg -> Int
+ GHC.StgToJS.Regs: jsRegsFromR1 :: [JExpr]
+ GHC.StgToJS.Regs: jsRegsFromR2 :: [JExpr]
+ GHC.StgToJS.Regs: maxReg :: Int
+ GHC.StgToJS.Regs: minReg :: Int
+ GHC.StgToJS.Regs: r1 :: JExpr
+ GHC.StgToJS.Regs: r2 :: JExpr
+ GHC.StgToJS.Regs: r3 :: JExpr
+ GHC.StgToJS.Regs: r4 :: JExpr
+ GHC.StgToJS.Regs: regsFromR1 :: [StgReg]
+ GHC.StgToJS.Regs: regsFromR2 :: [StgReg]
+ GHC.StgToJS.Regs: sp :: JExpr
+ GHC.StgToJS.Regs: stack :: JExpr
+ GHC.StgToJS.Rts.Rts: assignRegs :: StgToJSConfig -> [JExpr] -> JStat
+ GHC.StgToJS.Rts.Rts: assignRegs' :: Array Int Ident
+ GHC.StgToJS.Rts.Rts: bhLneStats :: StgToJSConfig -> JExpr -> JExpr -> JStat
+ GHC.StgToJS.Rts.Rts: bitsIdx :: Integer -> [Int]
+ GHC.StgToJS.Rts.Rts: closureConstructors :: StgToJSConfig -> JStat
+ GHC.StgToJS.Rts.Rts: closureTypes :: JStat
+ GHC.StgToJS.Rts.Rts: declRegs :: JStat
+ GHC.StgToJS.Rts.Rts: declRets :: JStat
+ GHC.StgToJS.Rts.Rts: garbageCollector :: JStat
+ GHC.StgToJS.Rts.Rts: loadRegs :: JStat
+ GHC.StgToJS.Rts.Rts: regGettersSetters :: JStat
+ GHC.StgToJS.Rts.Rts: resetRegister :: StgReg -> JStat
+ GHC.StgToJS.Rts.Rts: resetResultVar :: StgRet -> JStat
+ GHC.StgToJS.Rts.Rts: rts :: StgToJSConfig -> JStat
+ GHC.StgToJS.Rts.Rts: rts' :: StgToJSConfig -> JStat
+ GHC.StgToJS.Rts.Rts: rtsDecls :: JStat
+ GHC.StgToJS.Rts.Rts: rtsDeclsText :: String
+ GHC.StgToJS.Rts.Rts: rtsText :: StgToJSConfig -> String
+ GHC.StgToJS.Rts.Rts: stackManip :: JStat
+ GHC.StgToJS.Rts.Types: assertRts :: ToJExpr a => StgToJSConfig -> JExpr -> a -> JStat
+ GHC.StgToJS.Rts.Types: clName :: JExpr -> JExpr
+ GHC.StgToJS.Rts.Types: clTypeName :: JExpr -> JExpr
+ GHC.StgToJS.Rts.Types: stackFrameSize :: JExpr -> JExpr -> JStat
+ GHC.StgToJS.Rts.Types: traceRts :: StgToJSConfig -> JExpr -> JStat
+ GHC.StgToJS.Rts.Types: withRegs :: StgReg -> StgReg -> (StgReg -> JStat) -> JStat
+ GHC.StgToJS.Sinker: sinkPgm :: Module -> [CgStgTopBinding] -> (UniqFM Id CgStgExpr, [CgStgTopBinding])
+ GHC.StgToJS.Stack: addSlots :: [StackSlot] -> G ()
+ GHC.StgToJS.Stack: addUnknownSlots :: Int -> G ()
+ GHC.StgToJS.Stack: adjSp :: Int -> G JStat
+ GHC.StgToJS.Stack: adjSp' :: Int -> JStat
+ GHC.StgToJS.Stack: adjSpN :: Int -> G JStat
+ GHC.StgToJS.Stack: adjSpN' :: Int -> JStat
+ GHC.StgToJS.Stack: bhStats :: StgToJSConfig -> Bool -> JStat
+ GHC.StgToJS.Stack: dropSlots :: Int -> G ()
+ GHC.StgToJS.Stack: getSlots :: G [StackSlot]
+ GHC.StgToJS.Stack: isolateSlots :: G a -> G a
+ GHC.StgToJS.Stack: loadSkip :: Int -> [JExpr] -> JStat
+ GHC.StgToJS.Stack: popN :: Int -> G JStat
+ GHC.StgToJS.Stack: popSkip :: Int -> [JExpr] -> JStat
+ GHC.StgToJS.Stack: popSkipI :: Int -> [(Ident, StackSlot)] -> G JStat
+ GHC.StgToJS.Stack: push :: [JExpr] -> G JStat
+ GHC.StgToJS.Stack: push' :: StgToJSConfig -> [JExpr] -> JStat
+ GHC.StgToJS.Stack: pushLneFrame :: HasDebugCallStack => Int -> ExprCtx -> G JStat
+ GHC.StgToJS.Stack: pushN :: Array Int Ident
+ GHC.StgToJS.Stack: pushN' :: Array Int JExpr
+ GHC.StgToJS.Stack: pushNN :: Array Integer Ident
+ GHC.StgToJS.Stack: pushNN' :: Array Integer JExpr
+ GHC.StgToJS.Stack: pushOptimized :: [(JExpr, Bool)] -> G JStat
+ GHC.StgToJS.Stack: pushOptimized' :: [(Id, Int)] -> G JStat
+ GHC.StgToJS.Stack: resetSlots :: G a -> G a
+ GHC.StgToJS.Stack: setSlots :: [StackSlot] -> G ()
+ GHC.StgToJS.Stack: updateThunk :: G JStat
+ GHC.StgToJS.Stack: updateThunk' :: StgToJSConfig -> JStat
+ GHC.StgToJS.StaticPtr: initStaticPtrs :: [SptEntry] -> G JStat
+ GHC.StgToJS.StgUtils: bindingRefs :: UniqFM Id CgStgExpr -> CgStgBinding -> Set Id
+ GHC.StgToJS.StgUtils: collectIds :: UniqFM Id CgStgExpr -> CgStgBinding -> [Id]
+ GHC.StgToJS.StgUtils: collectTopIds :: CgStgBinding -> [Id]
+ GHC.StgToJS.StgUtils: exprRefs :: UniqFM Id CgStgExpr -> CgStgExpr -> Set Id
+ GHC.StgToJS.StgUtils: hasExport :: CgStgBinding -> Bool
+ GHC.StgToJS.StgUtils: isInlineExpr :: UniqSet Id -> CgStgExpr -> (UniqSet Id, Bool)
+ GHC.StgToJS.StgUtils: isUpdatableRhs :: CgStgRhs -> Bool
+ GHC.StgToJS.StgUtils: liveStatic :: LiveVars -> LiveVars
+ GHC.StgToJS.StgUtils: liveVars :: LiveVars -> LiveVars
+ GHC.StgToJS.StgUtils: removeTick :: CgStgExpr -> CgStgExpr
+ GHC.StgToJS.StgUtils: stgExprLive :: Bool -> CgStgExpr -> LiveVars
+ GHC.StgToJS.StgUtils: stgLetNoEscapeLive :: Bool -> StgBinding -> StgExpr -> LiveVars
+ GHC.StgToJS.StgUtils: stgLneLive :: CgStgBinding -> [Id]
+ GHC.StgToJS.StgUtils: stgLneLive' :: CgStgBinding -> [Id]
+ GHC.StgToJS.StgUtils: stgLneLiveExpr :: CgStgRhs -> [Id]
+ GHC.StgToJS.StgUtils: stgRhsLive :: CgStgRhs -> LiveVars
+ GHC.StgToJS.StgUtils: stgTopBindLive :: CgStgTopBinding -> [(Id, LiveVars)]
+ GHC.StgToJS.StgUtils: type LiveVars = DVarSet
+ GHC.StgToJS.Symbols: intBS :: Int -> ByteString
+ GHC.StgToJS.Symbols: mkFreshJsSymbol :: Module -> Int -> FastString
+ GHC.StgToJS.Symbols: mkJsSymbol :: Bool -> Module -> FastString -> FastString
+ GHC.StgToJS.Symbols: mkJsSymbolBS :: Bool -> Module -> FastString -> ByteString
+ GHC.StgToJS.Symbols: mkRawSymbol :: Bool -> FastString -> FastString
+ GHC.StgToJS.Symbols: moduleExportsSymbol :: Module -> FastString
+ GHC.StgToJS.Symbols: moduleGlobalSymbol :: Module -> FastString
+ GHC.StgToJS.Types: AddrV :: VarType
+ GHC.StgToJS.Types: ArrV :: VarType
+ GHC.StgToJS.Types: BinLit :: !ByteString -> StaticLit
+ GHC.StgToJS.Types: Blackhole :: ClosureType
+ GHC.StgToJS.Types: Blocked :: ThreadStatus
+ GHC.StgToJS.Types: BoolLit :: !Bool -> StaticLit
+ GHC.StgToJS.Types: ByteArrayType :: JSFFIType
+ GHC.StgToJS.Types: CIBlackhole :: CIType
+ GHC.StgToJS.Types: CICon :: !Int -> CIType
+ GHC.StgToJS.Types: CIFun :: !Int -> !Int -> CIType
+ GHC.StgToJS.Types: CILayoutFixed :: !Int -> [VarType] -> CILayout
+ GHC.StgToJS.Types: CILayoutUnknown :: !Int -> CILayout
+ GHC.StgToJS.Types: CILayoutVariable :: CILayout
+ GHC.StgToJS.Types: CIPap :: CIType
+ GHC.StgToJS.Types: CIRegs :: Int -> [VarType] -> CIRegs
+ GHC.StgToJS.Types: CIRegsUnknown :: CIRegs
+ GHC.StgToJS.Types: CIStackFrame :: CIType
+ GHC.StgToJS.Types: CIStaticRefs :: [FastString] -> CIStatic
+ GHC.StgToJS.Types: CIThunk :: CIType
+ GHC.StgToJS.Types: ClosureInfo :: Ident -> CIRegs -> FastString -> CILayout -> CIType -> CIStatic -> ClosureInfo
+ GHC.StgToJS.Types: Con :: ClosureType
+ GHC.StgToJS.Types: Died :: ThreadStatus
+ GHC.StgToJS.Types: DoubleLit :: !SaneDouble -> StaticLit
+ GHC.StgToJS.Types: DoubleType :: JSFFIType
+ GHC.StgToJS.Types: DoubleV :: VarType
+ GHC.StgToJS.Types: ExpFun :: !Bool -> [JSFFIType] -> !JSFFIType -> ExpFun
+ GHC.StgToJS.Types: ExprCont :: ExprResult
+ GHC.StgToJS.Types: ExprInline :: Maybe [JExpr] -> ExprResult
+ GHC.StgToJS.Types: ExprValData :: [JExpr] -> ExprValData
+ GHC.StgToJS.Types: Finished :: ThreadStatus
+ GHC.StgToJS.Types: ForeignJSRef :: !FastString -> !FastString -> !Safety -> !CCallConv -> ![FastString] -> !FastString -> ForeignJSRef
+ GHC.StgToJS.Types: Fun :: ClosureType
+ GHC.StgToJS.Types: GenGroupState :: [JStat] -> [ClosureInfo] -> [StaticInfo] -> [StackSlot] -> Int -> Set OtherSymb -> GlobalIdCache -> [ForeignJSRef] -> GenGroupState
+ GHC.StgToJS.Types: GenState :: !StgToJSConfig -> !Module -> {-# UNPACK #-} !FastMutInt -> !IdCache -> !UniqFM Id CgStgExpr -> GenGroupState -> [JStat] -> GenState
+ GHC.StgToJS.Types: GlobalIdCache :: UniqFM Ident (IdKey, Id) -> GlobalIdCache
+ GHC.StgToJS.Types: IdCache :: Map IdKey Ident -> IdCache
+ GHC.StgToJS.Types: IdConEntry :: IdType
+ GHC.StgToJS.Types: IdEntry :: IdType
+ GHC.StgToJS.Types: IdKey :: !Int -> !Int -> !IdType -> IdKey
+ GHC.StgToJS.Types: IdPlain :: IdType
+ GHC.StgToJS.Types: Int16Type :: JSFFIType
+ GHC.StgToJS.Types: Int32Type :: JSFFIType
+ GHC.StgToJS.Types: Int64Type :: JSFFIType
+ GHC.StgToJS.Types: Int8Type :: JSFFIType
+ GHC.StgToJS.Types: IntLit :: !Integer -> StaticLit
+ GHC.StgToJS.Types: IntV :: VarType
+ GHC.StgToJS.Types: LabelLit :: !Bool -> !FastString -> StaticLit
+ GHC.StgToJS.Types: LinkableUnit :: ObjUnit -> [Id] -> [FastString] -> [Id] -> [Unique] -> [OtherSymb] -> Bool -> [ForeignJSRef] -> LinkableUnit
+ GHC.StgToJS.Types: LongV :: VarType
+ GHC.StgToJS.Types: NullLit :: StaticLit
+ GHC.StgToJS.Types: ObjUnit :: ![FastString] -> ![ClosureInfo] -> ![StaticInfo] -> JStat -> !ByteString -> ![ExpFun] -> ![ForeignJSRef] -> ObjUnit
+ GHC.StgToJS.Types: ObjV :: VarType
+ GHC.StgToJS.Types: OtherSymb :: !Module -> !FastString -> OtherSymb
+ GHC.StgToJS.Types: PRPrimCall :: JStat -> PrimRes
+ GHC.StgToJS.Types: Pap :: ClosureType
+ GHC.StgToJS.Types: PrimInline :: JStat -> PrimRes
+ GHC.StgToJS.Types: PtrType :: JSFFIType
+ GHC.StgToJS.Types: PtrV :: VarType
+ GHC.StgToJS.Types: RefType :: JSFFIType
+ GHC.StgToJS.Types: RtsObjV :: VarType
+ GHC.StgToJS.Types: Running :: ThreadStatus
+ GHC.StgToJS.Types: SlotId :: !Id -> !Int -> StackSlot
+ GHC.StgToJS.Types: SlotUnknown :: StackSlot
+ GHC.StgToJS.Types: StackFrame :: ClosureType
+ GHC.StgToJS.Types: StaticConArg :: !FastString -> [StaticArg] -> StaticArg
+ GHC.StgToJS.Types: StaticData :: !FastString -> [StaticArg] -> StaticVal
+ GHC.StgToJS.Types: StaticFun :: !FastString -> [StaticArg] -> StaticVal
+ GHC.StgToJS.Types: StaticInfo :: !FastString -> !StaticVal -> !Maybe Ident -> StaticInfo
+ GHC.StgToJS.Types: StaticList :: [StaticArg] -> Maybe FastString -> StaticVal
+ GHC.StgToJS.Types: StaticLitArg :: !StaticLit -> StaticArg
+ GHC.StgToJS.Types: StaticObjArg :: !FastString -> StaticArg
+ GHC.StgToJS.Types: StaticThunk :: !Maybe (FastString, [StaticArg]) -> StaticVal
+ GHC.StgToJS.Types: StaticUnboxed :: !StaticUnboxed -> StaticVal
+ GHC.StgToJS.Types: StaticUnboxedBool :: !Bool -> StaticUnboxed
+ GHC.StgToJS.Types: StaticUnboxedDouble :: !SaneDouble -> StaticUnboxed
+ GHC.StgToJS.Types: StaticUnboxedInt :: !Integer -> StaticUnboxed
+ GHC.StgToJS.Types: StaticUnboxedString :: !ByteString -> StaticUnboxed
+ GHC.StgToJS.Types: StaticUnboxedStringOffset :: !ByteString -> StaticUnboxed
+ GHC.StgToJS.Types: StgToJSConfig :: !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !SDocContext -> StgToJSConfig
+ GHC.StgToJS.Types: StringLit :: !FastString -> StaticLit
+ GHC.StgToJS.Types: Thunk :: ClosureType
+ GHC.StgToJS.Types: TypedExpr :: !PrimRep -> [JExpr] -> TypedExpr
+ GHC.StgToJS.Types: VoidV :: VarType
+ GHC.StgToJS.Types: Word16Type :: JSFFIType
+ GHC.StgToJS.Types: Word32Type :: JSFFIType
+ GHC.StgToJS.Types: Word64Type :: JSFFIType
+ GHC.StgToJS.Types: Word8Type :: JSFFIType
+ GHC.StgToJS.Types: [args] :: ExpFun -> [JSFFIType]
+ GHC.StgToJS.Types: [ciLayout] :: ClosureInfo -> CILayout
+ GHC.StgToJS.Types: [ciName] :: ClosureInfo -> FastString
+ GHC.StgToJS.Types: [ciRegsSkip] :: CIRegs -> Int
+ GHC.StgToJS.Types: [ciRegsTypes] :: CIRegs -> [VarType]
+ GHC.StgToJS.Types: [ciRegs] :: ClosureInfo -> CIRegs
+ GHC.StgToJS.Types: [ciStatic] :: ClosureInfo -> CIStatic
+ GHC.StgToJS.Types: [ciType] :: ClosureInfo -> CIType
+ GHC.StgToJS.Types: [ciVar] :: ClosureInfo -> Ident
+ GHC.StgToJS.Types: [citArity] :: CIType -> !Int
+ GHC.StgToJS.Types: [citConstructor] :: CIType -> !Int
+ GHC.StgToJS.Types: [citRegs] :: CIType -> !Int
+ GHC.StgToJS.Types: [csAssertRts] :: StgToJSConfig -> !Bool
+ GHC.StgToJS.Types: [csBoundsCheck] :: StgToJSConfig -> !Bool
+ GHC.StgToJS.Types: [csContext] :: StgToJSConfig -> !SDocContext
+ GHC.StgToJS.Types: [csDebugAlloc] :: StgToJSConfig -> !Bool
+ GHC.StgToJS.Types: [csInlineAlloc] :: StgToJSConfig -> !Bool
+ GHC.StgToJS.Types: [csInlineBlackhole] :: StgToJSConfig -> !Bool
+ GHC.StgToJS.Types: [csInlineEnter] :: StgToJSConfig -> !Bool
+ GHC.StgToJS.Types: [csInlineLoadRegs] :: StgToJSConfig -> !Bool
+ GHC.StgToJS.Types: [csInlinePush] :: StgToJSConfig -> !Bool
+ GHC.StgToJS.Types: [csProf] :: StgToJSConfig -> !Bool
+ GHC.StgToJS.Types: [csRuntimeAssert] :: StgToJSConfig -> !Bool
+ GHC.StgToJS.Types: [csTraceForeign] :: StgToJSConfig -> !Bool
+ GHC.StgToJS.Types: [csTraceRts] :: StgToJSConfig -> !Bool
+ GHC.StgToJS.Types: [foreignRefArgs] :: ForeignJSRef -> ![FastString]
+ GHC.StgToJS.Types: [foreignRefCConv] :: ForeignJSRef -> !CCallConv
+ GHC.StgToJS.Types: [foreignRefPattern] :: ForeignJSRef -> !FastString
+ GHC.StgToJS.Types: [foreignRefResult] :: ForeignJSRef -> !FastString
+ GHC.StgToJS.Types: [foreignRefSafety] :: ForeignJSRef -> !Safety
+ GHC.StgToJS.Types: [foreignRefSrcSpan] :: ForeignJSRef -> !FastString
+ GHC.StgToJS.Types: [ggsClosureInfo] :: GenGroupState -> [ClosureInfo]
+ GHC.StgToJS.Types: [ggsExtraDeps] :: GenGroupState -> Set OtherSymb
+ GHC.StgToJS.Types: [ggsForeignRefs] :: GenGroupState -> [ForeignJSRef]
+ GHC.StgToJS.Types: [ggsGlobalIdCache] :: GenGroupState -> GlobalIdCache
+ GHC.StgToJS.Types: [ggsStackDepth] :: GenGroupState -> Int
+ GHC.StgToJS.Types: [ggsStack] :: GenGroupState -> [StackSlot]
+ GHC.StgToJS.Types: [ggsStatic] :: GenGroupState -> [StaticInfo]
+ GHC.StgToJS.Types: [ggsToplevelStats] :: GenGroupState -> [JStat]
+ GHC.StgToJS.Types: [gsGlobal] :: GenState -> [JStat]
+ GHC.StgToJS.Types: [gsGroup] :: GenState -> GenGroupState
+ GHC.StgToJS.Types: [gsId] :: GenState -> {-# UNPACK #-} !FastMutInt
+ GHC.StgToJS.Types: [gsIdents] :: GenState -> !IdCache
+ GHC.StgToJS.Types: [gsModule] :: GenState -> !Module
+ GHC.StgToJS.Types: [gsSettings] :: GenState -> !StgToJSConfig
+ GHC.StgToJS.Types: [gsUnfloated] :: GenState -> !UniqFM Id CgStgExpr
+ GHC.StgToJS.Types: [isIO] :: ExpFun -> !Bool
+ GHC.StgToJS.Types: [layoutSize] :: CILayout -> !Int
+ GHC.StgToJS.Types: [layout] :: CILayout -> [VarType]
+ GHC.StgToJS.Types: [luForeignRefs] :: LinkableUnit -> [ForeignJSRef]
+ GHC.StgToJS.Types: [luIdDeps] :: LinkableUnit -> [Id]
+ GHC.StgToJS.Types: [luIdExports] :: LinkableUnit -> [Id]
+ GHC.StgToJS.Types: [luObjUnit] :: LinkableUnit -> ObjUnit
+ GHC.StgToJS.Types: [luOtherDeps] :: LinkableUnit -> [OtherSymb]
+ GHC.StgToJS.Types: [luOtherExports] :: LinkableUnit -> [FastString]
+ GHC.StgToJS.Types: [luPseudoIdDeps] :: LinkableUnit -> [Unique]
+ GHC.StgToJS.Types: [luRequired] :: LinkableUnit -> Bool
+ GHC.StgToJS.Types: [oiClInfo] :: ObjUnit -> ![ClosureInfo]
+ GHC.StgToJS.Types: [oiFExports] :: ObjUnit -> ![ExpFun]
+ GHC.StgToJS.Types: [oiFImports] :: ObjUnit -> ![ForeignJSRef]
+ GHC.StgToJS.Types: [oiRaw] :: ObjUnit -> !ByteString
+ GHC.StgToJS.Types: [oiStat] :: ObjUnit -> JStat
+ GHC.StgToJS.Types: [oiStatic] :: ObjUnit -> ![StaticInfo]
+ GHC.StgToJS.Types: [oiSymbols] :: ObjUnit -> ![FastString]
+ GHC.StgToJS.Types: [result] :: ExpFun -> !JSFFIType
+ GHC.StgToJS.Types: [siCC] :: StaticInfo -> !Maybe Ident
+ GHC.StgToJS.Types: [siVal] :: StaticInfo -> !StaticVal
+ GHC.StgToJS.Types: [siVar] :: StaticInfo -> !FastString
+ GHC.StgToJS.Types: [staticRefs] :: CIStatic -> [FastString]
+ GHC.StgToJS.Types: [typex_expr] :: TypedExpr -> [JExpr]
+ GHC.StgToJS.Types: [typex_typ] :: TypedExpr -> !PrimRep
+ GHC.StgToJS.Types: ctJsName :: ClosureType -> String
+ GHC.StgToJS.Types: ctNum :: ClosureType -> Int
+ GHC.StgToJS.Types: data CILayout
+ GHC.StgToJS.Types: data CIRegs
+ GHC.StgToJS.Types: data CIType
+ GHC.StgToJS.Types: data ClosureInfo
+ GHC.StgToJS.Types: data ClosureType
+ GHC.StgToJS.Types: data ExpFun
+ GHC.StgToJS.Types: data ExprResult
+ GHC.StgToJS.Types: data ForeignJSRef
+ GHC.StgToJS.Types: data GenGroupState
+ GHC.StgToJS.Types: data GenState
+ GHC.StgToJS.Types: data IdKey
+ GHC.StgToJS.Types: data IdType
+ GHC.StgToJS.Types: data JSFFIType
+ GHC.StgToJS.Types: data LinkableUnit
+ GHC.StgToJS.Types: data ObjUnit
+ GHC.StgToJS.Types: data OtherSymb
+ GHC.StgToJS.Types: data PrimRes
+ GHC.StgToJS.Types: data StackSlot
+ GHC.StgToJS.Types: data StaticArg
+ GHC.StgToJS.Types: data StaticInfo
+ GHC.StgToJS.Types: data StaticLit
+ GHC.StgToJS.Types: data StaticUnboxed
+ GHC.StgToJS.Types: data StaticVal
+ GHC.StgToJS.Types: data StgToJSConfig
+ GHC.StgToJS.Types: data ThreadStatus
+ GHC.StgToJS.Types: data TypedExpr
+ GHC.StgToJS.Types: data VarType
+ GHC.StgToJS.Types: instance Control.DeepSeq.NFData GHC.StgToJS.Types.CILayout
+ GHC.StgToJS.Types: instance Control.DeepSeq.NFData GHC.StgToJS.Types.CIRegs
+ GHC.StgToJS.Types: instance Control.DeepSeq.NFData GHC.StgToJS.Types.CIType
+ GHC.StgToJS.Types: instance Control.DeepSeq.NFData GHC.StgToJS.Types.StaticUnboxed
+ GHC.StgToJS.Types: instance Control.DeepSeq.NFData GHC.StgToJS.Types.VarType
+ GHC.StgToJS.Types: instance GHC.Base.Monoid GHC.StgToJS.Types.CIStatic
+ GHC.StgToJS.Types: instance GHC.Base.Semigroup GHC.StgToJS.Types.CIStatic
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.CILayout
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.CIRegs
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.CIStatic
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.CIType
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.ClosureInfo
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.ClosureType
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.ExpFun
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.ExprResult
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.ExprValData
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.IdKey
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.IdType
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.JSFFIType
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.OtherSymb
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.StackSlot
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.StaticArg
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.StaticInfo
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.StaticLit
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.StaticUnboxed
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.StaticVal
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.ThreadStatus
+ GHC.StgToJS.Types: instance GHC.Classes.Eq GHC.StgToJS.Types.VarType
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.CILayout
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.CIRegs
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.CIType
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.ClosureType
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.ExpFun
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.IdKey
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.IdType
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.JSFFIType
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.OtherSymb
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.StackSlot
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.StaticUnboxed
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.ThreadStatus
+ GHC.StgToJS.Types: instance GHC.Classes.Ord GHC.StgToJS.Types.VarType
+ GHC.StgToJS.Types: instance GHC.Enum.Bounded GHC.StgToJS.Types.ClosureType
+ GHC.StgToJS.Types: instance GHC.Enum.Bounded GHC.StgToJS.Types.ThreadStatus
+ GHC.StgToJS.Types: instance GHC.Enum.Bounded GHC.StgToJS.Types.VarType
+ GHC.StgToJS.Types: instance GHC.Enum.Enum GHC.StgToJS.Types.ClosureType
+ GHC.StgToJS.Types: instance GHC.Enum.Enum GHC.StgToJS.Types.IdType
+ GHC.StgToJS.Types: instance GHC.Enum.Enum GHC.StgToJS.Types.JSFFIType
+ GHC.StgToJS.Types: instance GHC.Enum.Enum GHC.StgToJS.Types.ThreadStatus
+ GHC.StgToJS.Types: instance GHC.Enum.Enum GHC.StgToJS.Types.VarType
+ GHC.StgToJS.Types: instance GHC.Generics.Generic GHC.StgToJS.Types.CILayout
+ GHC.StgToJS.Types: instance GHC.Generics.Generic GHC.StgToJS.Types.CIRegs
+ GHC.StgToJS.Types: instance GHC.Generics.Generic GHC.StgToJS.Types.CIStatic
+ GHC.StgToJS.Types: instance GHC.Generics.Generic GHC.StgToJS.Types.CIType
+ GHC.StgToJS.Types: instance GHC.Generics.Generic GHC.StgToJS.Types.ClosureInfo
+ GHC.StgToJS.Types: instance GHC.Generics.Generic GHC.StgToJS.Types.ForeignJSRef
+ GHC.StgToJS.Types: instance GHC.Generics.Generic GHC.StgToJS.Types.StaticArg
+ GHC.StgToJS.Types: instance GHC.Generics.Generic GHC.StgToJS.Types.StaticInfo
+ GHC.StgToJS.Types: instance GHC.Generics.Generic GHC.StgToJS.Types.StaticLit
+ GHC.StgToJS.Types: instance GHC.Generics.Generic GHC.StgToJS.Types.StaticUnboxed
+ GHC.StgToJS.Types: instance GHC.Generics.Generic GHC.StgToJS.Types.StaticVal
+ GHC.StgToJS.Types: instance GHC.Generics.Generic GHC.StgToJS.Types.VarType
+ GHC.StgToJS.Types: instance GHC.JS.Make.ToJExpr GHC.StgToJS.Types.CIStatic
+ GHC.StgToJS.Types: instance GHC.JS.Make.ToJExpr GHC.StgToJS.Types.ClosureType
+ GHC.StgToJS.Types: instance GHC.JS.Make.ToJExpr GHC.StgToJS.Types.StaticLit
+ GHC.StgToJS.Types: instance GHC.JS.Make.ToJExpr GHC.StgToJS.Types.VarType
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.CILayout
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.CIRegs
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.CIStatic
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.CIType
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.ClosureInfo
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.ClosureType
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.ExpFun
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.JSFFIType
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.StaticArg
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.StaticInfo
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.StaticLit
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.StaticUnboxed
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.StaticVal
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.ThreadStatus
+ GHC.StgToJS.Types: instance GHC.Show.Show GHC.StgToJS.Types.VarType
+ GHC.StgToJS.Types: instance GHC.Utils.Outputable.Outputable GHC.StgToJS.Types.StaticArg
+ GHC.StgToJS.Types: instance GHC.Utils.Outputable.Outputable GHC.StgToJS.Types.StaticLit
+ GHC.StgToJS.Types: instance GHC.Utils.Outputable.Outputable GHC.StgToJS.Types.TypedExpr
+ GHC.StgToJS.Types: newtype CIStatic
+ GHC.StgToJS.Types: newtype ExprValData
+ GHC.StgToJS.Types: newtype GlobalIdCache
+ GHC.StgToJS.Types: newtype IdCache
+ GHC.StgToJS.Types: threadStatusJsName :: ThreadStatus -> String
+ GHC.StgToJS.Types: threadStatusNum :: ThreadStatus -> Int
+ GHC.StgToJS.Types: type G = StateT GenState IO
+ GHC.StgToJS.Utils: assignCoerce1 :: HasDebugCallStack => [TypedExpr] -> [TypedExpr] -> JStat
+ GHC.StgToJS.Utils: assignToExprCtx :: HasDebugCallStack => ExprCtx -> [JExpr] -> JStat
+ GHC.StgToJS.Utils: assignToTypedExprs :: HasDebugCallStack => [TypedExpr] -> [JExpr] -> JStat
+ GHC.SysTools.Tasks: runEmscripten :: Logger -> DynFlags -> [Option] -> IO ()
+ GHC.Tc.Utils.Monad: getNamePprCtx :: TcRn NamePprCtx
+ GHC.Wasm.ControlFlow: (<>) :: forall s e pre mid post. WasmControl s e pre mid -> WasmControl s e mid post -> WasmControl s e pre post
+ GHC.Wasm.ControlFlow: BrTableInterval :: Integer -> Integer -> BrTableInterval
+ GHC.Wasm.ControlFlow: WasmFunctionType :: TypeList pre -> TypeList post -> WasmFunctionType pre post
+ GHC.Wasm.ControlFlow: [TagF32] :: WasmTypeTag 'F32
+ GHC.Wasm.ControlFlow: [TagF64] :: WasmTypeTag 'F64
+ GHC.Wasm.ControlFlow: [TagI32] :: WasmTypeTag 'I32
+ GHC.Wasm.ControlFlow: [TagI64] :: WasmTypeTag 'I64
+ GHC.Wasm.ControlFlow: [TypeListCons] :: WasmTypeTag t -> TypeList ts -> TypeList (t : ts)
+ GHC.Wasm.ControlFlow: [TypeListNil] :: TypeList '[]
+ GHC.Wasm.ControlFlow: [WasmActions] :: s -> WasmControl s e stack stack
+ GHC.Wasm.ControlFlow: [WasmBlock] :: WasmFunctionType pre post -> WasmControl s e pre post -> WasmControl s e pre post
+ GHC.Wasm.ControlFlow: [WasmBrTable] :: e -> BrTableInterval -> [Int] -> Int -> WasmControl s e dropped destination
+ GHC.Wasm.ControlFlow: [WasmBr] :: Int -> WasmControl s e dropped destination
+ GHC.Wasm.ControlFlow: [WasmFallthrough] :: WasmControl s e dropped destination
+ GHC.Wasm.ControlFlow: [WasmIfTop] :: WasmFunctionType pre post -> WasmControl s e pre post -> WasmControl s e pre post -> WasmControl s e ('I32 : pre) post
+ GHC.Wasm.ControlFlow: [WasmLoop] :: WasmFunctionType pre post -> WasmControl s e pre post -> WasmControl s e pre post
+ GHC.Wasm.ControlFlow: [WasmPush] :: WasmTypeTag t -> e -> WasmControl s e stack (t : stack)
+ GHC.Wasm.ControlFlow: [WasmReturnTop] :: WasmTypeTag t -> WasmControl s e (t : t1star) t2star
+ GHC.Wasm.ControlFlow: [WasmSeq] :: WasmControl s e pre mid -> WasmControl s e mid post -> WasmControl s e pre post
+ GHC.Wasm.ControlFlow: [bti_count] :: BrTableInterval -> Integer
+ GHC.Wasm.ControlFlow: [bti_lo] :: BrTableInterval -> Integer
+ GHC.Wasm.ControlFlow: [ft_pops] :: WasmFunctionType pre post -> TypeList pre
+ GHC.Wasm.ControlFlow: [ft_pushes] :: WasmFunctionType pre post -> TypeList post
+ GHC.Wasm.ControlFlow: data BrTableInterval
+ GHC.Wasm.ControlFlow: data TypeList :: [WasmType] -> Type
+ GHC.Wasm.ControlFlow: data WasmControl :: Type -> Type -> [WasmType] -> [WasmType] -> Type
+ GHC.Wasm.ControlFlow: data WasmFunctionType pre post
+ GHC.Wasm.ControlFlow: data WasmType
+ GHC.Wasm.ControlFlow: data WasmTypeTag :: WasmType -> Type
+ GHC.Wasm.ControlFlow: inclusiveInterval :: Integer -> Integer -> BrTableInterval
+ GHC.Wasm.ControlFlow: pattern WasmIf :: WasmFunctionType pre post -> e -> WasmControl s e pre post -> WasmControl s e pre post -> WasmControl s e pre post
+ GHC.Wasm.ControlFlow: wasmReturn :: WasmTypeTag t -> e -> WasmControl s e (t : t1star) t2star
+ GHC.Wasm.ControlFlow.FromCmm: instance GHC.Utils.Outputable.Outputable GHC.Wasm.ControlFlow.FromCmm.ContainingSyntax
+ GHC.Wasm.ControlFlow.FromCmm: instance GHC.Utils.Outputable.Outputable GHC.Wasm.ControlFlow.FromCmm.Context
+ GHC.Wasm.ControlFlow.FromCmm: structuredControl :: forall expr stmt m. Applicative m => Platform -> (Label -> CmmExpr -> m expr) -> (Label -> CmmActions -> m stmt) -> CmmGraph -> m (WasmControl stmt expr '[] '[ 'I32])
- GHC: alwaysQualify :: PrintUnqualified
+ GHC: alwaysQualify :: NamePprCtx
- GHC: funResultTy :: Type -> Type
+ GHC: funResultTy :: HasDebugCallStack => Type -> Type
- GHC: pprForAll :: [TyCoVarBinder] -> SDoc
+ GHC: pprForAll :: [ForAllTyBinder] -> SDoc
- GHC: pprModule :: Module -> SDoc
+ GHC: pprModule :: IsLine doc => Module -> doc
- GHC.Cmm.Utils: mkFileEmbedLit :: CLabel -> FilePath -> (CmmLit, GenCmmDecl (GenCmmStatics raw) info stmt)
+ GHC.Cmm.Utils: mkFileEmbedLit :: CLabel -> FilePath -> Int -> (CmmLit, GenCmmDecl (GenCmmStatics raw) info stmt)
- GHC.CmmToAsm: NcgImpl :: !NCGConfig -> (RawCmmDecl -> NatM [NatCmmDecl statics instr]) -> (instr -> Maybe (NatCmmDecl statics instr)) -> (jumpDest -> Maybe BlockId) -> (instr -> Maybe jumpDest) -> ((BlockId -> Maybe jumpDest) -> statics -> statics) -> ((BlockId -> Maybe jumpDest) -> instr -> instr) -> (NatCmmDecl statics instr -> SDoc) -> Int -> [RealReg] -> (Int -> NatCmmDecl statics instr -> UniqSM (NatCmmDecl statics instr, [(BlockId, BlockId)])) -> (LabelMap RawCmmStatics -> [NatBasicBlock instr] -> [NatBasicBlock instr]) -> ([instr] -> [UnwindPoint]) -> (Maybe CFG -> LabelMap RawCmmStatics -> [NatBasicBlock instr] -> [NatBasicBlock instr]) -> NcgImpl statics instr jumpDest
+ GHC.CmmToAsm: NcgImpl :: !NCGConfig -> (RawCmmDecl -> NatM [NatCmmDecl statics instr]) -> (instr -> Maybe (NatCmmDecl statics instr)) -> (jumpDest -> Maybe BlockId) -> (instr -> Maybe jumpDest) -> ((BlockId -> Maybe jumpDest) -> statics -> statics) -> ((BlockId -> Maybe jumpDest) -> instr -> instr) -> (NatCmmDecl statics instr -> SDoc) -> (NatCmmDecl statics instr -> HDoc) -> Int -> [RealReg] -> (Int -> NatCmmDecl statics instr -> UniqSM (NatCmmDecl statics instr, [(BlockId, BlockId)])) -> (LabelMap RawCmmStatics -> [NatBasicBlock instr] -> [NatBasicBlock instr]) -> ([instr] -> [UnwindPoint]) -> (Maybe CFG -> LabelMap RawCmmStatics -> [NatBasicBlock instr] -> [NatBasicBlock instr]) -> NcgImpl statics instr jumpDest
- GHC.CmmToAsm.AArch64.Ppr: pprInstr :: Platform -> Instr -> SDoc
+ GHC.CmmToAsm.AArch64.Ppr: pprInstr :: IsDoc doc => Platform -> Instr -> doc
- GHC.CmmToAsm.AArch64.Ppr: pprNatCmmDecl :: NCGConfig -> NatCmmDecl RawCmmStatics Instr -> SDoc
+ GHC.CmmToAsm.AArch64.Ppr: pprNatCmmDecl :: IsDoc doc => NCGConfig -> NatCmmDecl RawCmmStatics Instr -> doc
- GHC.CmmToAsm.AArch64.Regs: ImmLit :: String -> Imm
+ GHC.CmmToAsm.AArch64.Regs: ImmLit :: FastString -> Imm
- GHC.CmmToAsm.AArch64.Regs: strImmLit :: String -> Imm
+ GHC.CmmToAsm.AArch64.Regs: strImmLit :: FastString -> Imm
- GHC.CmmToAsm.Dwarf: dwarfGen :: NCGConfig -> ModLocation -> UniqSupply -> [DebugBlock] -> IO (SDoc, UniqSupply)
+ GHC.CmmToAsm.Dwarf: dwarfGen :: IsDoc doc => String -> NCGConfig -> ModLocation -> UniqSupply -> [DebugBlock] -> (doc, UniqSupply)
- GHC.CmmToAsm.Dwarf.Constants: dwarfARangesSection :: Platform -> SDoc
+ GHC.CmmToAsm.Dwarf.Constants: dwarfARangesSection :: IsDoc doc => Platform -> doc
- GHC.CmmToAsm.Dwarf.Constants: dwarfAbbrevLabel :: SDoc
+ GHC.CmmToAsm.Dwarf.Constants: dwarfAbbrevLabel :: IsLine doc => doc
- GHC.CmmToAsm.Dwarf.Constants: dwarfAbbrevSection :: Platform -> SDoc
+ GHC.CmmToAsm.Dwarf.Constants: dwarfAbbrevSection :: IsDoc doc => Platform -> doc
- GHC.CmmToAsm.Dwarf.Constants: dwarfFrameLabel :: SDoc
+ GHC.CmmToAsm.Dwarf.Constants: dwarfFrameLabel :: IsLine doc => doc
- GHC.CmmToAsm.Dwarf.Constants: dwarfFrameSection :: Platform -> SDoc
+ GHC.CmmToAsm.Dwarf.Constants: dwarfFrameSection :: IsDoc doc => Platform -> doc
- GHC.CmmToAsm.Dwarf.Constants: dwarfGhcSection :: Platform -> SDoc
+ GHC.CmmToAsm.Dwarf.Constants: dwarfGhcSection :: IsDoc doc => Platform -> doc
- GHC.CmmToAsm.Dwarf.Constants: dwarfInfoLabel :: SDoc
+ GHC.CmmToAsm.Dwarf.Constants: dwarfInfoLabel :: IsLine doc => doc
- GHC.CmmToAsm.Dwarf.Constants: dwarfInfoSection :: Platform -> SDoc
+ GHC.CmmToAsm.Dwarf.Constants: dwarfInfoSection :: IsDoc doc => Platform -> doc
- GHC.CmmToAsm.Dwarf.Constants: dwarfLineLabel :: SDoc
+ GHC.CmmToAsm.Dwarf.Constants: dwarfLineLabel :: IsLine doc => doc
- GHC.CmmToAsm.Dwarf.Constants: dwarfLineSection :: Platform -> SDoc
+ GHC.CmmToAsm.Dwarf.Constants: dwarfLineSection :: IsDoc doc => Platform -> doc
- GHC.CmmToAsm.Dwarf.Constants: dwarfSection :: Platform -> String -> SDoc
+ GHC.CmmToAsm.Dwarf.Constants: dwarfSection :: IsDoc doc => Platform -> String -> doc
- GHC.CmmToAsm.Dwarf.Types: DwarfCompileUnit :: [DwarfInfo] -> String -> String -> String -> SDoc -> SDoc -> SDoc -> DwarfInfo
+ GHC.CmmToAsm.Dwarf.Types: DwarfCompileUnit :: [DwarfInfo] -> String -> String -> String -> CLabel -> CLabel -> DwarfInfo
- GHC.CmmToAsm.Dwarf.Types: [dwHighLabel] :: DwarfInfo -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: [dwHighLabel] :: DwarfInfo -> CLabel
- GHC.CmmToAsm.Dwarf.Types: [dwLowLabel] :: DwarfInfo -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: [dwLowLabel] :: DwarfInfo -> CLabel
- GHC.CmmToAsm.Dwarf.Types: pprAbbrevDecls :: Platform -> Bool -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: pprAbbrevDecls :: IsDoc doc => Platform -> Bool -> doc
- GHC.CmmToAsm.Dwarf.Types: pprByte :: Word8 -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: pprByte :: IsDoc doc => Word8 -> doc
- GHC.CmmToAsm.Dwarf.Types: pprData4' :: SDoc -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: pprData4' :: IsDoc doc => Line doc -> doc
- GHC.CmmToAsm.Dwarf.Types: pprDwWord :: SDoc -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: pprDwWord :: IsDoc doc => Line doc -> doc
- GHC.CmmToAsm.Dwarf.Types: pprDwarfARanges :: Platform -> [DwarfARange] -> Unique -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: pprDwarfARanges :: IsDoc doc => Platform -> [DwarfARange] -> Unique -> doc
- GHC.CmmToAsm.Dwarf.Types: pprDwarfFrame :: Platform -> DwarfFrame -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: pprDwarfFrame :: forall doc. IsDoc doc => Platform -> DwarfFrame -> doc
- GHC.CmmToAsm.Dwarf.Types: pprDwarfInfo :: Platform -> Bool -> DwarfInfo -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: pprDwarfInfo :: IsDoc doc => Platform -> Bool -> DwarfInfo -> doc
- GHC.CmmToAsm.Dwarf.Types: pprHalf :: Word16 -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: pprHalf :: IsDoc doc => Word16 -> doc
- GHC.CmmToAsm.Dwarf.Types: pprLEBInt :: Int -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: pprLEBInt :: IsDoc doc => Int -> doc
- GHC.CmmToAsm.Dwarf.Types: pprLEBWord :: Word -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: pprLEBWord :: IsDoc doc => Word -> doc
- GHC.CmmToAsm.Dwarf.Types: pprWord :: Platform -> SDoc -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: pprWord :: IsDoc doc => Platform -> Line doc -> doc
- GHC.CmmToAsm.Dwarf.Types: sectionOffset :: Platform -> SDoc -> SDoc -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: sectionOffset :: IsDoc doc => Platform -> Line doc -> Line doc -> doc
- GHC.CmmToAsm.Dwarf.Types: wordAlign :: Platform -> SDoc
+ GHC.CmmToAsm.Dwarf.Types: wordAlign :: IsDoc doc => Platform -> doc
- GHC.CmmToAsm.Instr: mkComment :: Instruction instr => SDoc -> [instr]
+ GHC.CmmToAsm.Instr: mkComment :: Instruction instr => FastString -> [instr]
- GHC.CmmToAsm.Monad: NcgImpl :: !NCGConfig -> (RawCmmDecl -> NatM [NatCmmDecl statics instr]) -> (instr -> Maybe (NatCmmDecl statics instr)) -> (jumpDest -> Maybe BlockId) -> (instr -> Maybe jumpDest) -> ((BlockId -> Maybe jumpDest) -> statics -> statics) -> ((BlockId -> Maybe jumpDest) -> instr -> instr) -> (NatCmmDecl statics instr -> SDoc) -> Int -> [RealReg] -> (Int -> NatCmmDecl statics instr -> UniqSM (NatCmmDecl statics instr, [(BlockId, BlockId)])) -> (LabelMap RawCmmStatics -> [NatBasicBlock instr] -> [NatBasicBlock instr]) -> ([instr] -> [UnwindPoint]) -> (Maybe CFG -> LabelMap RawCmmStatics -> [NatBasicBlock instr] -> [NatBasicBlock instr]) -> NcgImpl statics instr jumpDest
+ GHC.CmmToAsm.Monad: NcgImpl :: !NCGConfig -> (RawCmmDecl -> NatM [NatCmmDecl statics instr]) -> (instr -> Maybe (NatCmmDecl statics instr)) -> (jumpDest -> Maybe BlockId) -> (instr -> Maybe jumpDest) -> ((BlockId -> Maybe jumpDest) -> statics -> statics) -> ((BlockId -> Maybe jumpDest) -> instr -> instr) -> (NatCmmDecl statics instr -> SDoc) -> (NatCmmDecl statics instr -> HDoc) -> Int -> [RealReg] -> (Int -> NatCmmDecl statics instr -> UniqSM (NatCmmDecl statics instr, [(BlockId, BlockId)])) -> (LabelMap RawCmmStatics -> [NatBasicBlock instr] -> [NatBasicBlock instr]) -> ([instr] -> [UnwindPoint]) -> (Maybe CFG -> LabelMap RawCmmStatics -> [NatBasicBlock instr] -> [NatBasicBlock instr]) -> NcgImpl statics instr jumpDest
- GHC.CmmToAsm.PIC: pprGotDeclaration :: NCGConfig -> SDoc
+ GHC.CmmToAsm.PIC: pprGotDeclaration :: NCGConfig -> HDoc
- GHC.CmmToAsm.PIC: pprImportedSymbol :: NCGConfig -> CLabel -> SDoc
+ GHC.CmmToAsm.PIC: pprImportedSymbol :: NCGConfig -> CLabel -> HDoc
- GHC.CmmToAsm.PPC.Instr: COMMENT :: SDoc -> Instr
+ GHC.CmmToAsm.PPC.Instr: COMMENT :: FastString -> Instr
- GHC.CmmToAsm.PPC.Ppr: pprInstr :: Platform -> Instr -> SDoc
+ GHC.CmmToAsm.PPC.Ppr: pprInstr :: IsDoc doc => Platform -> Instr -> doc
- GHC.CmmToAsm.PPC.Ppr: pprNatCmmDecl :: NCGConfig -> NatCmmDecl RawCmmStatics Instr -> SDoc
+ GHC.CmmToAsm.PPC.Ppr: pprNatCmmDecl :: IsDoc doc => NCGConfig -> NatCmmDecl RawCmmStatics Instr -> doc
- GHC.CmmToAsm.PPC.Regs: ImmLit :: String -> Imm
+ GHC.CmmToAsm.PPC.Regs: ImmLit :: FastString -> Imm
- GHC.CmmToAsm.PPC.Regs: strImmLit :: String -> Imm
+ GHC.CmmToAsm.PPC.Regs: strImmLit :: FastString -> Imm
- GHC.CmmToAsm.Ppr: pprASCII :: ByteString -> SDoc
+ GHC.CmmToAsm.Ppr: pprASCII :: forall doc. IsLine doc => ByteString -> doc
- GHC.CmmToAsm.Ppr: pprFileEmbed :: FilePath -> SDoc
+ GHC.CmmToAsm.Ppr: pprFileEmbed :: IsLine doc => FilePath -> doc
- GHC.CmmToAsm.Ppr: pprSectionHeader :: NCGConfig -> Section -> SDoc
+ GHC.CmmToAsm.Ppr: pprSectionHeader :: IsLine doc => NCGConfig -> Section -> doc
- GHC.CmmToAsm.Ppr: pprString :: ByteString -> SDoc
+ GHC.CmmToAsm.Ppr: pprString :: IsLine doc => ByteString -> doc
- GHC.CmmToAsm.X86.Instr: COMMENT :: SDoc -> Instr
+ GHC.CmmToAsm.X86.Instr: COMMENT :: FastString -> Instr
- GHC.CmmToAsm.X86.Ppr: pprInstr :: Platform -> Instr -> SDoc
+ GHC.CmmToAsm.X86.Ppr: pprInstr :: forall doc. IsDoc doc => Platform -> Instr -> doc
- GHC.CmmToAsm.X86.Ppr: pprNatCmmDecl :: NCGConfig -> NatCmmDecl (Alignment, RawCmmStatics) Instr -> SDoc
+ GHC.CmmToAsm.X86.Ppr: pprNatCmmDecl :: IsDoc doc => NCGConfig -> NatCmmDecl (Alignment, RawCmmStatics) Instr -> doc
- GHC.CmmToAsm.X86.Regs: ImmLit :: String -> Imm
+ GHC.CmmToAsm.X86.Regs: ImmLit :: FastString -> Imm
- GHC.CmmToAsm.X86.Regs: strImmLit :: String -> Imm
+ GHC.CmmToAsm.X86.Regs: strImmLit :: FastString -> Imm
- GHC.Core.Opt.WorkWrap.Utils: mkWWstr :: WwOpts -> [Var] -> [StrictnessMark] -> UniqSM (Bool, [(Var, StrictnessMark)], CoreExpr -> CoreExpr, [CoreExpr])
+ GHC.Core.Opt.WorkWrap.Utils: mkWWstr :: WwOpts -> [Var] -> [StrictnessMark] -> UniqSM (WwUse, [(Var, StrictnessMark)], CoreExpr -> CoreExpr, [CoreExpr])
- GHC.Core.Opt.WorkWrap.Utils: mkWWstr_one :: WwOpts -> Var -> StrictnessMark -> UniqSM (Bool, [(Var, StrictnessMark)], CoreExpr -> CoreExpr, CoreExpr)
+ GHC.Core.Opt.WorkWrap.Utils: mkWWstr_one :: WwOpts -> Var -> StrictnessMark -> UniqSM (WwUse, [(Var, StrictnessMark)], CoreExpr -> CoreExpr, CoreExpr)
- GHC.HsToCore.Binds: decomposeRuleLhs :: DynFlags -> [Var] -> CoreExpr -> Either DsMessage ([Var], Id, [CoreExpr])
+ GHC.HsToCore.Binds: decomposeRuleLhs :: DynFlags -> [Var] -> CoreExpr -> VarSet -> Either DsMessage ([Var], Id, [CoreExpr])
- GHC.HsToCore.Types: DsGblEnv :: Module -> FamInstEnv -> GlobalRdrEnv -> PrintUnqualified -> IORef (Messages DsMessage) -> (IfGblEnv, IfLclEnv) -> CompleteMatches -> IORef CostCentreState -> IORef (ModuleEnv Int) -> DsGblEnv
+ GHC.HsToCore.Types: DsGblEnv :: Module -> FamInstEnv -> GlobalRdrEnv -> NamePprCtx -> IORef (Messages DsMessage) -> (IfGblEnv, IfLclEnv) -> CompleteMatches -> IORef CostCentreState -> IORef (ModuleEnv Int) -> DsGblEnv
- GHC.Iface.Binary: putName :: BinDictionary -> BinSymbolTable -> BinHandle -> Name -> IO ()
+ GHC.Iface.Binary: putName :: FSTable -> BinSymbolTable -> BinHandle -> Name -> IO ()
- GHC.Iface.Ext.Types: HForAllTy :: ((Name, a), ArgFlag) -> a -> HieType a
+ GHC.Iface.Ext.Types: HForAllTy :: ((Name, a), ForAllTyFlag) -> a -> HieType a
- GHC.Iface.Recomp: ModulePackageChanged :: String -> RecompReason
+ GHC.Iface.Recomp: ModulePackageChanged :: FastString -> RecompReason
- GHC.Plugins: Invisible :: Specificity -> ArgFlag
+ GHC.Plugins: Invisible :: Specificity -> ForAllTyFlag
- GHC.Plugins: Required :: ArgFlag
+ GHC.Plugins: Required :: ForAllTyFlag
- GHC.Plugins: TyCoFolder :: (Type -> Maybe Type) -> (env -> TyVar -> a) -> (env -> CoVar -> a) -> (env -> CoercionHole -> a) -> (env -> TyCoVar -> ArgFlag -> env) -> TyCoFolder env a
+ GHC.Plugins: TyCoFolder :: (Type -> Maybe Type) -> (env -> TyVar -> a) -> (env -> CoVar -> a) -> (env -> CoercionHole -> a) -> (env -> TyCoVar -> ForAllTyFlag -> env) -> TyCoFolder env a
- GHC.Plugins: TyCoMapper :: (env -> TyVar -> m Type) -> (env -> CoVar -> m Coercion) -> (env -> CoercionHole -> m Coercion) -> (env -> TyCoVar -> ArgFlag -> m (env, TyCoVar)) -> (TyCon -> m TyCon) -> TyCoMapper env (m :: Type -> Type)
+ GHC.Plugins: TyCoMapper :: (env -> TyVar -> m Type) -> (env -> CoVar -> m Coercion) -> (env -> CoercionHole -> m Coercion) -> (env -> TyCoVar -> ForAllTyFlag -> m (env, TyCoVar)) -> (TyCon -> m TyCon) -> TyCoMapper env (m :: Type -> Type)
- GHC.Plugins: [tcf_tycobinder] :: TyCoFolder env a -> env -> TyCoVar -> ArgFlag -> env
+ GHC.Plugins: [tcf_tycobinder] :: TyCoFolder env a -> env -> TyCoVar -> ForAllTyFlag -> env
- GHC.Plugins: [tcm_tycobinder] :: TyCoMapper env (m :: Type -> Type) -> env -> TyCoVar -> ArgFlag -> m (env, TyCoVar)
+ GHC.Plugins: [tcm_tycobinder] :: TyCoMapper env (m :: Type -> Type) -> env -> TyCoVar -> ForAllTyFlag -> m (env, TyCoVar)
- GHC.Plugins: decomposeCo :: Arity -> Coercion -> [Role] -> [Coercion]
+ GHC.Plugins: decomposeCo :: Arity -> Coercion -> Infinite Role -> [Coercion]
- GHC.Plugins: decomposeFunCo :: HasDebugCallStack => Role -> Coercion -> (CoercionN, Coercion, Coercion)
+ GHC.Plugins: decomposeFunCo :: HasDebugCallStack => Coercion -> (CoercionN, Coercion, Coercion)
- GHC.Plugins: extendTvSubstBinderAndInScope :: Subst -> TyCoBinder -> Type -> Subst
+ GHC.Plugins: extendTvSubstBinderAndInScope :: Subst -> PiTyBinder -> Type -> Subst
- GHC.Plugins: funResultTy :: Type -> Type
+ GHC.Plugins: funResultTy :: HasDebugCallStack => Type -> Type
- GHC.Plugins: getRuntimeArgTys :: Type -> [(Scaled Type, AnonArgFlag)]
+ GHC.Plugins: getRuntimeArgTys :: Type -> [(Scaled Type, FunTyFlag)]
- GHC.Plugins: getTyVar :: String -> Type -> TyVar
+ GHC.Plugins: getTyVar :: HasDebugCallStack => Type -> TyVar
- GHC.Plugins: isBoxedRuntimeRep :: Type -> Bool
+ GHC.Plugins: isBoxedRuntimeRep :: RuntimeRepType -> Bool
- GHC.Plugins: isLiftedRuntimeRep :: Type -> Bool
+ GHC.Plugins: isLiftedRuntimeRep :: RuntimeRepType -> Bool
- GHC.Plugins: isUnliftedRuntimeRep :: Type -> Bool
+ GHC.Plugins: isUnliftedRuntimeRep :: RuntimeRepType -> Bool
- GHC.Plugins: mkFCallName :: Unique -> String -> Name
+ GHC.Plugins: mkFCallName :: Unique -> FastString -> Name
- GHC.Plugins: mkForAllTy :: TyCoVar -> ArgFlag -> Type -> Type
+ GHC.Plugins: mkForAllTy :: ForAllTyBinder -> Type -> Type
- GHC.Plugins: mkForAllTys :: [TyCoVarBinder] -> Type -> Type
+ GHC.Plugins: mkForAllTys :: [ForAllTyBinder] -> Type -> Type
- GHC.Plugins: mkFunResCo :: Role -> Scaled Type -> Coercion -> Coercion
+ GHC.Plugins: mkFunResCo :: Role -> Id -> Coercion -> Coercion
- GHC.Plugins: mkFunResMCo :: Scaled Type -> MCoercionR -> MCoercionR
+ GHC.Plugins: mkFunResMCo :: Id -> MCoercionR -> MCoercionR
- GHC.Plugins: mkFunTy :: AnonArgFlag -> Mult -> Type -> Type -> Type
+ GHC.Plugins: mkFunTy :: HasDebugCallStack => FunTyFlag -> Mult -> Type -> Type -> Type
- GHC.Plugins: mkInstCo :: Coercion -> Coercion -> Coercion
+ GHC.Plugins: mkInstCo :: Coercion -> CoercionN -> Coercion
- GHC.Plugins: mkInvisFunTy :: Mult -> Type -> Type -> Type
+ GHC.Plugins: mkInvisFunTy :: HasDebugCallStack => Type -> Type -> Type
- GHC.Plugins: mkPiTy :: TyCoBinder -> Type -> Type
+ GHC.Plugins: mkPiTy :: PiTyBinder -> Type -> Type
- GHC.Plugins: mkPiTys :: [TyCoBinder] -> Type -> Type
+ GHC.Plugins: mkPiTys :: [PiTyBinder] -> Type -> Type
- GHC.Plugins: mkVisFunTy :: Mult -> Type -> Type -> Type
+ GHC.Plugins: mkVisFunTy :: HasDebugCallStack => Mult -> Type -> Type -> Type
- GHC.Plugins: mkVisFunTyMany :: Type -> Type -> Type
+ GHC.Plugins: mkVisFunTyMany :: HasDebugCallStack => Type -> Type -> Type
- GHC.Plugins: partitionInvisibles :: [(a, ArgFlag)] -> ([a], [a])
+ GHC.Plugins: partitionInvisibles :: [(a, ForAllTyFlag)] -> ([a], [a])
- GHC.Plugins: pattern Inferred :: ArgFlag
+ GHC.Plugins: pattern Inferred :: ForAllTyFlag
- GHC.Plugins: pattern Specified :: ArgFlag
+ GHC.Plugins: pattern Specified :: ForAllTyFlag
- GHC.Plugins: pprModulePrefix :: PprStyle -> Module -> OccName -> SDoc
+ GHC.Plugins: pprModulePrefix :: IsLine doc => PprStyle -> Module -> OccName -> doc
- GHC.Plugins: pprNameSpaceBrief :: NameSpace -> SDoc
+ GHC.Plugins: pprNameSpaceBrief :: IsLine doc => NameSpace -> doc
- GHC.Plugins: pprOccName :: OccName -> SDoc
+ GHC.Plugins: pprOccName :: IsLine doc => OccName -> doc
- GHC.Plugins: runtimeRepLevity_maybe :: Type -> Maybe Levity
+ GHC.Plugins: runtimeRepLevity_maybe :: RuntimeRepType -> Maybe Levity
- GHC.Plugins: splitForAllCoVar_maybe :: Type -> Maybe (TyCoVar, Type)
+ GHC.Plugins: splitForAllCoVar_maybe :: Type -> Maybe (CoVar, Type)
- GHC.Plugins: splitForAllTyVar_maybe :: Type -> Maybe (TyCoVar, Type)
+ GHC.Plugins: splitForAllTyVar_maybe :: Type -> Maybe (TyVar, Type)
- GHC.Plugins: splitFunTy_maybe :: Type -> Maybe (Mult, Type, Type)
+ GHC.Plugins: splitFunTy_maybe :: Type -> Maybe (FunTyFlag, Mult, Type, Type)
- GHC.Plugins: splitInvisPiTys :: Type -> ([TyCoBinder], Type)
+ GHC.Plugins: splitInvisPiTys :: Type -> ([PiTyBinder], Type)
- GHC.Plugins: splitInvisPiTysN :: Int -> Type -> ([TyCoBinder], Type)
+ GHC.Plugins: splitInvisPiTysN :: Int -> Type -> ([PiTyBinder], Type)
- GHC.Plugins: splitPiTy :: Type -> (TyCoBinder, Type)
+ GHC.Plugins: splitPiTy :: Type -> (PiTyBinder, Type)
- GHC.Plugins: splitPiTy_maybe :: Type -> Maybe (TyCoBinder, Type)
+ GHC.Plugins: splitPiTy_maybe :: Type -> Maybe (PiTyBinder, Type)
- GHC.Plugins: splitPiTys :: Type -> ([TyCoBinder], Type)
+ GHC.Plugins: splitPiTys :: Type -> ([PiTyBinder], Type)
- GHC.Plugins: substBndrs :: Subst -> [Var] -> (Subst, [Var])
+ GHC.Plugins: substBndrs :: Traversable f => Subst -> f Var -> (Subst, f Var)
- GHC.Plugins: substRecBndrs :: Subst -> [Id] -> (Subst, [Id])
+ GHC.Plugins: substRecBndrs :: Traversable f => Subst -> f Id -> (Subst, f Id)
- GHC.Plugins: substTyCoBndr :: Subst -> TyCoBinder -> (Subst, TyCoBinder)
+ GHC.Plugins: substTyCoBndr :: Subst -> PiTyBinder -> (Subst, PiTyBinder)
- GHC.Plugins: tyCoFVsBndr :: TyCoVarBinder -> FV -> FV
+ GHC.Plugins: tyCoFVsBndr :: ForAllTyBinder -> FV -> FV
- GHC.Plugins: tyConRolesRepresentational :: TyCon -> [Role]
+ GHC.Plugins: tyConRolesRepresentational :: TyCon -> Infinite Role
- GHC.Plugins: tyConRolesX :: Role -> TyCon -> [Role]
+ GHC.Plugins: tyConRolesX :: Role -> TyCon -> Infinite Role
- GHC.Plugins: tyVarSpecToBinders :: [VarBndr a Specificity] -> [VarBndr a ArgFlag]
+ GHC.Plugins: tyVarSpecToBinders :: [VarBndr a Specificity] -> [VarBndr a ForAllTyFlag]
- GHC.Plugins: type TyVarBinder = VarBndr TyVar ArgFlag
+ GHC.Plugins: type TyVarBinder = VarBndr TyVar ForAllTyFlag
- GHC.Plugins: typeHasFixedRuntimeRep :: Type -> Bool
+ GHC.Plugins: typeHasFixedRuntimeRep :: HasDebugCallStack => Type -> Bool
- GHC.Rename.Expr: type AnnoBody body = (Outputable (body GhcPs), Anno (StmtLR GhcPs GhcPs (LocatedA (body GhcPs))) ~ SrcSpanAnnA, Anno (StmtLR GhcRn GhcPs (LocatedA (body GhcPs))) ~ SrcSpanAnnA, Anno (StmtLR GhcRn GhcRn (LocatedA (body GhcRn))) ~ SrcSpanAnnA)
+ GHC.Rename.Expr: type AnnoBody body = (Outputable (body GhcPs))
- GHC.Rename.Pat: rnOverLit :: HsOverLit t -> RnM ((HsOverLit GhcRn, Maybe (HsExpr GhcRn)), FreeVars)
+ GHC.Rename.Pat: rnOverLit :: XXOverLit t ~ DataConCantHappen => HsOverLit t -> RnM ((HsOverLit GhcRn, Maybe (HsExpr GhcRn)), FreeVars)
- GHC.Rename.Pat: rnPats :: HsMatchContext GhcRn -> [LPat GhcPs] -> ([LPat GhcRn] -> RnM (a, FreeVars)) -> RnM (a, FreeVars)
+ GHC.Rename.Pat: rnPats :: Traversable f => HsMatchContext GhcRn -> f (LPat GhcPs) -> (f (LPat GhcRn) -> RnM (a, FreeVars)) -> RnM (a, FreeVars)
- GHC.Tc.Utils.Instantiate: tcInstInvisibleTyBinder :: Subst -> TyBinder -> TcM (Subst, TcType)
+ GHC.Tc.Utils.Instantiate: tcInstInvisibleTyBinder :: Subst -> PiTyVarBinder -> TcM (Subst, TcType)
- GHC.Utils.Asm: sectionType :: Platform -> String -> SDoc
+ GHC.Utils.Asm: sectionType :: IsLine doc => Platform -> String -> doc

Files

compiler/CodeGen.Platform.h view
@@ -664,7 +664,8 @@ #if defined(MACHREGS_i386) || defined(MACHREGS_x86_64) \     || defined(MACHREGS_powerpc) \     || defined(MACHREGS_arm) || defined(MACHREGS_aarch64) \-    || defined(MACHREGS_s390x) || defined(MACHREGS_riscv64)+    || defined(MACHREGS_s390x) || defined(MACHREGS_riscv64) \+    || defined(MACHREGS_wasm32) # if defined(REG_Base) globalRegMaybe BaseReg                  = Just (RealRegSingle REG_Base) # endif
compiler/GHC.hs view
@@ -97,12 +97,12 @@         modInfoSafe,         lookupGlobalName,         findGlobalAnns,-        mkPrintUnqualifiedForModule,+        mkNamePprCtxForModule,         ModIface, ModIface_(..),         SafeHaskellMode(..),          -- * Printing-        PrintUnqualified, alwaysQualify,+        NamePprCtx, alwaysQualify,          -- * Interactive evaluation @@ -119,7 +119,7 @@         setGHCiMonad, getGHCiMonad,          -- ** Inspecting the current context-        getBindings, getInsts, getPrintUnqual,+        getBindings, getInsts, getNamePprCtx,         findModule, lookupModule,         findQualifiedModule, lookupQualifiedModule,         renamePkgQualM, renameRawPkgQualM,@@ -197,7 +197,7 @@         TyCon,         tyConTyVars, tyConDataCons, tyConArity,         isClassTyCon, isTypeSynonymTyCon, isTypeFamilyTyCon, isNewTyCon,-        isPrimTyCon, isFunTyCon,+        isPrimTyCon,         isFamilyTyCon, isOpenFamilyTyCon, isOpenTypeFamilyTyCon,         tyConClass_maybe,         synTyConRhs_maybe, synTyConDefn_maybe, tyConKind,@@ -1346,9 +1346,9 @@     let (inst_env, fam_env) = ic_instances (hsc_IC hsc_env)     in return (instEnvElts inst_env, fam_env) -getPrintUnqual :: GhcMonad m => m PrintUnqualified-getPrintUnqual = withSession $ \hsc_env -> do-  return $ icPrintUnqual (hsc_unit_env hsc_env) (hsc_IC hsc_env)+getNamePprCtx :: GhcMonad m => m NamePprCtx+getNamePprCtx = withSession $ \hsc_env -> do+  return $ icNamePprCtx (hsc_unit_env hsc_env) (hsc_IC hsc_env)  -- | Container for information about a 'Module'. data ModuleInfo = ModuleInfo {@@ -1442,12 +1442,14 @@ modInfoIsExportedName :: ModuleInfo -> Name -> Bool modInfoIsExportedName minf name = elemNameSet name (availsToNameSet (minf_exports minf)) -mkPrintUnqualifiedForModule :: GhcMonad m =>-                               ModuleInfo-                            -> m (Maybe PrintUnqualified) -- XXX: returns a Maybe X-mkPrintUnqualifiedForModule minf = withSession $ \hsc_env -> do-  let mk_print_unqual = mkPrintUnqualified (hsc_unit_env hsc_env)-  return (fmap mk_print_unqual (minf_rdr_env minf))+mkNamePprCtxForModule ::+  GhcMonad m =>+  ModuleInfo ->+  m (Maybe NamePprCtx) -- XXX: returns a Maybe X+mkNamePprCtxForModule minf = withSession $ \hsc_env -> do+  let mk_name_ppr_ctx = mkNamePprCtx ptc (hsc_unit_env hsc_env)+      ptc = initPromotionTickContext (hsc_dflags hsc_env)+  return (fmap mk_name_ppr_ctx (minf_rdr_env minf))  modInfoLookupName :: GhcMonad m =>                      ModuleInfo -> Name
+ compiler/GHC/Builtin/PrimOps/Casts.hs view
@@ -0,0 +1,212 @@+{-+This module contains helpers to cast variables+between different Int/WordReps in StgLand.++-}++module GHC.Builtin.PrimOps.Casts+    ( getCasts )+where++import GHC.Prelude++import GHC.Core.TyCon+import GHC.Utils.Outputable+import GHC.Utils.Panic+import GHC.Utils.Panic.Plain+import GHC.Types.RepType+import GHC.Core.Type+import GHC.Builtin.Types.Prim++import GHC.Builtin.PrimOps+import GHC.Plugins (HasDebugCallStack)++{- Note [PrimRep based casting]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This module contains a number of utility functions useful when+converting between variables of differing PrimReps.++The general pattern is:+* We have two primReps `from_rep` and `to_rep`.+* We want a list of PrimOps we can apply to a variable of rep `from_rep`.+Applying the list of primOps in order takes us to `to_rep` from `from_rep` giving+us a variable of the returned type at each step.++E.g. we call `getCasts from_rep to_rep` and get back [(op1#,ty1),(op2#,ty2)].+We can use this result to construct a function of type+`StgExpr -> StgExpr` by construction an expression++    case op1# <from> of (x' :: ty1) -> case op2# x' of x' -> <rhs_hole>++Ideally backends will compile the sequence of PrimOps to a no-op. E.g. by reusing+the same register but just relabeling it as another width.+However this is might not always be possible or the required optimizations+simply not implemented in the backend. This means currently many of these casts+will be cheap but not all of them will be completely zero-cost.++-}++-- | `getCasts from_rep to_rep` gives us a list of primops which when applied in order convert from_rep to to_rep.+-- See Note [PrimRep based casting]+getCasts :: PrimRep -> PrimRep -> [(PrimOp,Type)]+getCasts from_rep to_rep+  -- No-op+  | -- pprTrace "getCasts" (ppr (from_rep,to_rep)) $+    to_rep == from_rep+  = []++  -- Float <-> Double+  | to_rep == FloatRep =+    assertPpr (from_rep == DoubleRep) (ppr from_rep <+> ppr to_rep) $+    [(DoubleToFloatOp,floatPrimTy)]+  | to_rep == DoubleRep =+    assertPpr (from_rep == FloatRep) (ppr from_rep <+> ppr to_rep) $+    [(FloatToDoubleOp,doublePrimTy)]++  -- Addr <-> Word/Int+  | to_rep == AddrRep = wordOrIntToAddrRep from_rep+  | from_rep == AddrRep = addrToWordOrIntRep to_rep++  -- Int* -> Int*+  | primRepIsInt from_rep+  , primRepIsInt to_rep+  = sizedIntToSizedInt from_rep to_rep++  -- Word* -> Word*+  | primRepIsWord from_rep+  , primRepIsWord to_rep+  = sizedWordToSizedWord from_rep to_rep++  -- Word* -> Int*+  | primRepIsWord from_rep+  , primRepIsInt to_rep+  = let (op1,r1) = wordToIntRep from_rep+    in (op1,primRepToType r1):sizedIntToSizedInt r1 to_rep++  -- Int* -> Word*+  | primRepIsInt from_rep+  , primRepIsWord to_rep+  = let (op1,r1) = intToWordRep from_rep+    in (op1,primRepToType r1):sizedWordToSizedWord r1 to_rep++  | otherwise = pprPanic "getCasts:Unexpect rep combination"+                          (ppr (from_rep,to_rep))++wordOrIntToAddrRep :: HasDebugCallStack => PrimRep -> [(PrimOp,Type)]+wordOrIntToAddrRep AddrRep = [] -- No-op argument is already AddrRep+wordOrIntToAddrRep IntRep = [(IntToAddrOp, addrPrimTy)]+wordOrIntToAddrRep WordRep = [(WordToIntOp,intPrimTy), (IntToAddrOp,addrPrimTy)]+wordOrIntToAddrRep r+    | primRepIsInt r = (intToMachineInt r,intPrimTy):[(IntToAddrOp,addrPrimTy)]+    | primRepIsWord r =+        let (op1,r1) = wordToIntRep r+        in (op1, primRepToType r1):[(intToMachineInt r1,intPrimTy), (IntToAddrOp,addrPrimTy)]+    | otherwise = pprPanic "Rep not word or int rep" (ppr r)++addrToWordOrIntRep :: HasDebugCallStack => PrimRep -> [(PrimOp,Type)]+-- Machine sizes+addrToWordOrIntRep IntRep = [(AddrToIntOp, intPrimTy)]+addrToWordOrIntRep WordRep = [(AddrToIntOp,intPrimTy), (IntToWordOp,wordPrimTy)]+-- Explicitly sized reps+addrToWordOrIntRep r+    | primRepIsWord r = (AddrToIntOp,intPrimTy) : (IntToWordOp,wordPrimTy) : sizedWordToSizedWord WordRep r+    | primRepIsInt r = (AddrToIntOp,intPrimTy) : sizedIntToSizedInt IntRep r+    | otherwise = pprPanic "Target rep not word or int rep" (ppr r)+++-- WordX# -> IntX# (same size), argument is source rep+wordToIntRep :: HasDebugCallStack => PrimRep -> (PrimOp,PrimRep)+wordToIntRep rep+    = case rep of+        (WordRep) -> (WordToIntOp, IntRep)+        (Word8Rep) -> (Word8ToInt8Op, Int8Rep)+        (Word16Rep) -> (Word16ToInt16Op, Int16Rep)+        (Word32Rep) -> (Word32ToInt32Op, Int32Rep)+        (Word64Rep) -> (Word64ToInt64Op, Int64Rep)+        _ -> pprPanic "Rep not a wordRep" (ppr rep)++-- IntX# -> WordX#, argument is source rep+intToWordRep :: HasDebugCallStack => PrimRep -> (PrimOp,PrimRep)+intToWordRep rep+    = case rep of+        (IntRep) -> (IntToWordOp, WordRep)+        (Int8Rep) -> (Int8ToWord8Op, Word8Rep)+        (Int16Rep) -> (Int16ToWord16Op, Word16Rep)+        (Int32Rep) -> (Int32ToWord32Op, Word32Rep)+        (Int64Rep) -> (Int64ToWord64Op, Word64Rep)+        _ -> pprPanic "Rep not a wordRep" (ppr rep)++-- Casts between any size int to any other size of int+sizedIntToSizedInt :: HasDebugCallStack => PrimRep -> PrimRep -> [(PrimOp,Type)]+sizedIntToSizedInt r1 r2+    | r1 == r2 = []+-- Cast to Int#+sizedIntToSizedInt r IntRep = [(intToMachineInt r,intPrimTy)]+-- Cast from Int#+sizedIntToSizedInt IntRep r = [(intFromMachineInt r,primRepToType r)]+-- Sized to differently sized must go over machine word.+sizedIntToSizedInt r1 r2 = (intToMachineInt r1,intPrimTy) : [(intFromMachineInt r2,primRepToType r2)]++-- Casts between any size Word to any other size of Word+sizedWordToSizedWord :: HasDebugCallStack => PrimRep -> PrimRep -> [(PrimOp,Type)]+sizedWordToSizedWord r1 r2+    | r1 == r2 = []+-- Cast to Word#+sizedWordToSizedWord r WordRep = [(wordToMachineWord r,wordPrimTy)]+-- Cast from Word#+sizedWordToSizedWord WordRep r = [(wordFromMachineWord r, primRepToType r)]+-- Conversion between different non-machine sizes must go via machine word.+sizedWordToSizedWord r1 r2 = (wordToMachineWord r1,wordPrimTy) : [(wordFromMachineWord r2, primRepToType r2)]+++-- Prefer the definitions above this line if possible+----------------------+++-- Int*# to Int#+{-# INLINE intToMachineInt #-}+intToMachineInt :: HasDebugCallStack => PrimRep -> PrimOp+intToMachineInt r =+    assertPpr (primRepIsInt r) (ppr r) $+    case r of+        (Int8Rep) -> Int8ToIntOp+        (Int16Rep) -> Int16ToIntOp+        (Int32Rep) -> Int32ToIntOp+        (Int64Rep) -> Int64ToIntOp+        _ -> pprPanic "Source rep not int" $ ppr r++-- Int# to Int*#+{-# INLINE intFromMachineInt #-}+intFromMachineInt :: HasDebugCallStack => PrimRep -> PrimOp+intFromMachineInt r =+    assertPpr (primRepIsInt r) (ppr r) $+    case r of+        Int8Rep -> IntToInt8Op+        Int16Rep -> IntToInt16Op+        Int32Rep -> IntToInt32Op+        Int64Rep -> IntToInt64Op+        _ -> pprPanic "Dest rep not sized int" $ ppr r++-- Word# to Word*#+{-# INLINE wordFromMachineWord #-}+wordFromMachineWord :: HasDebugCallStack => PrimRep -> PrimOp+wordFromMachineWord r =+    assert (primRepIsWord r) $+    case r of+        Word8Rep -> WordToWord8Op+        Word16Rep -> WordToWord16Op+        Word32Rep -> WordToWord32Op+        Word64Rep -> WordToWord64Op+        _ -> pprPanic "Dest rep not sized word" $ ppr r++-- Word*# to Word#+{-# INLINE wordToMachineWord #-}+wordToMachineWord :: HasDebugCallStack => PrimRep -> PrimOp+wordToMachineWord r =+    assertPpr (primRepIsWord r) (text "Not a word rep:" <> ppr r) $+    case r of+        Word8Rep -> Word8ToWordOp+        Word16Rep -> Word16ToWordOp+        Word32Rep -> Word32ToWordOp+        Word64Rep -> Word64ToWordOp+        _ -> pprPanic "Dest rep not sized word" $ ppr r
compiler/GHC/Builtin/Types/Literals.hs view
@@ -29,12 +29,12 @@  import GHC.Core.Type import GHC.Data.Pair-import GHC.Tc.Utils.TcType ( TcType, tcEqType ) import GHC.Core.TyCon    ( TyCon, FamTyConFlav(..), mkFamilyTyCon                          , Injectivity(..) ) import GHC.Core.Coercion ( Role(..) ) import GHC.Tc.Types.Constraint ( Xi ) import GHC.Core.Coercion.Axiom ( CoAxiomRule(..), BuiltInSynFamily(..), TypeEqn )+import GHC.Core.TyCo.Compare   ( tcEqType ) import GHC.Types.Name          ( Name, BuiltInSyntax(..) ) import GHC.Types.Unique.FM import GHC.Builtin.Types@@ -630,7 +630,7 @@          | tc1 == promotedGTDataCon -> return GT          | otherwise                -> Nothing -known :: (Integer -> Bool) -> TcType -> Bool+known :: (Integer -> Bool) -> Type -> Bool known p x = case isNumLitTy x of               Just a  -> p a               Nothing -> False
compiler/GHC/Cmm/ContFlowOpt.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE BangPatterns #-}-{-# OPTIONS_GHC -Wno-incomplete-record-updates #-} module GHC.Cmm.ContFlowOpt     ( cmmCfgOpts     , cmmCfgOptsProc
compiler/GHC/Cmm/DebugBlock.hs view
@@ -29,7 +29,8 @@    -- * Unwinding information   UnwindTable, UnwindPoint(..),-  UnwindExpr(..), toUnwindExpr+  UnwindExpr(..), toUnwindExpr,+  pprUnwindTable   ) where  import GHC.Prelude@@ -38,6 +39,7 @@ import GHC.Cmm.BlockId import GHC.Cmm.CLabel import GHC.Cmm+import GHC.Cmm.Reg ( pprGlobalReg ) import GHC.Cmm.Utils import GHC.Data.FastString ( nilFS, mkFastString ) import GHC.Unit.Module@@ -522,10 +524,18 @@ instance OutputableP Platform UnwindExpr where   pdoc = pprUnwindExpr 0 -pprUnwindExpr :: Rational -> Platform -> UnwindExpr -> SDoc+pprUnwindTable :: IsLine doc => Platform -> UnwindTable -> doc+pprUnwindTable platform u = brackets (fsep (punctuate comma (map print_entry (Map.toList u))))+  where print_entry (reg, Nothing) =+          parens (sep [pprGlobalReg reg, text "Nothing"])+        print_entry (reg, Just x)  =+          parens (sep [pprGlobalReg reg, text "Just" <+> pprUnwindExpr 0 platform x])+  -- Follow instance Outputable (Map.Map GlobalReg (Maybe UnwindExpr))++pprUnwindExpr :: IsLine doc => Rational -> Platform -> UnwindExpr -> doc pprUnwindExpr p env = \case   UwConst i     -> int i-  UwReg g 0     -> ppr g+  UwReg g 0     -> pprGlobalReg g   UwReg g x     -> pprUnwindExpr p env (UwPlus (UwReg g 0) (UwConst x))   UwDeref e     -> char '*' <> pprUnwindExpr 3 env e   UwLabel l     -> pprAsmLabel env l@@ -536,6 +546,8 @@   UwTimes e0 e1    | p <= 1     -> pprUnwindExpr 2 env e0 <> char '*' <> pprUnwindExpr 2 env e1   other         -> parens (pprUnwindExpr 0 env other)+{-# SPECIALIZE pprUnwindExpr :: Rational -> Platform -> UnwindExpr -> SDoc #-}+{-# SPECIALIZE pprUnwindExpr :: Rational -> Platform -> UnwindExpr -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Conversion of Cmm expressions to unwind expressions. We check for -- unsupported operator usages and simplify the expression as far as
compiler/GHC/Cmm/Parser.y view
@@ -961,7 +961,6 @@         ( "ne",         MO_Ne ),         ( "mul",        MO_Mul ),         ( "mulmayoflo",  MO_S_MulMayOflo ),-        ( "mulmayoflou", MO_U_MulMayOflo ),         ( "neg",        MO_S_Neg ),         ( "quot",       MO_S_Quot ),         ( "rem",        MO_S_Rem ),
compiler/GHC/Cmm/ProcPoint.hs view
@@ -2,8 +2,6 @@ {-# LANGUAGE DisambiguateRecordFields #-} {-# LANGUAGE GADTs #-} -{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}- module GHC.Cmm.ProcPoint     ( ProcPointSet, Status(..)     , callProcPoints, minimalProcPointSet
+ compiler/GHC/Cmm/Reducibility.hs view
@@ -0,0 +1,224 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE MultiParamTypeClasses #-}++{-|+Module      : GHC.Cmm.Reducibility+Description : Tell if a `CmmGraph` is reducible, or make it so++Test a Cmm control-flow graph for reducibility.  And provide a+function that, when given an arbitrary control-flow graph, returns an+equivalent, reducible control-flow graph.  The equivalent graph is+obtained by "splitting" (copying) nodes of the original graph.+The resulting equivalent graph has the same dynamic behavior as the+original, but it is larger.++Documentation uses the language of control-flow analysis, in which a+basic block is called a "node."  These "nodes" are `CmmBlock`s or+equivalent; they have nothing to do with a `CmmNode`.++For more on reducibility and related analyses and algorithms, see+Note [Reducibility resources]+-}++module GHC.Cmm.Reducibility+  ( Reducibility(..)+  , reducibility++  , asReducible+  )+where++import GHC.Prelude hiding (splitAt, succ)++import Control.Monad+import Data.List (nub)+import Data.Maybe+import Data.Semigroup+import qualified Data.Sequence as Seq++import GHC.Cmm+import GHC.Cmm.BlockId+import GHC.Cmm.Dataflow+import GHC.Cmm.Dataflow.Collections+import GHC.Cmm.Dataflow.Block+import GHC.Cmm.Dominators+import GHC.Cmm.Dataflow.Graph hiding (addBlock)+import GHC.Cmm.Dataflow.Label+import GHC.Data.Graph.Collapse+import GHC.Data.Graph.Inductive.Graph+import GHC.Data.Graph.Inductive.PatriciaTree+import GHC.Types.Unique.Supply+import GHC.Utils.Panic++-- | Represents the result of a reducibility analysis.+data Reducibility = Reducible | Irreducible+  deriving (Eq, Show)++-- | Given a graph, say whether the graph is reducible.  The graph must+-- be bundled with a dominator analysis and a reverse postorder+-- numbering, as these results are needed to perform the test.++reducibility :: NonLocal node+             => GraphWithDominators node+             -> Reducibility+reducibility gwd =+    if all goodBlock blockmap then Reducible else Irreducible+  where goodBlock b = all (goodEdge (entryLabel b)) (successors b)+        goodEdge from to = rpnum to > rpnum from || to `dominates` from+        rpnum = gwdRPNumber gwd+        blockmap = graphMap $ gwd_graph gwd+        dominators = gwdDominatorsOf gwd+        dominates lbl blockname =+            lbl == blockname || dominatorsMember lbl (dominators blockname)++-- | Given a graph, return an equivalent reducible graph, by+-- "splitting" (copying) nodes if necessary.  The input+-- graph must be bundled with a dominator analysis and a reverse+-- postorder numbering.  The computation is monadic because when a+-- node is split, the new copy needs a fresh label.+--+-- Use this function whenever a downstream algorithm needs a reducible+-- control-flow graph.++asReducible :: GraphWithDominators CmmNode+            -> UniqSM (GraphWithDominators CmmNode)+asReducible gwd = case reducibility gwd of+                    Reducible -> return gwd+                    Irreducible -> assertReducible <$> nodeSplit gwd++assertReducible :: GraphWithDominators CmmNode -> GraphWithDominators CmmNode+assertReducible gwd = case reducibility gwd of+                        Reducible -> gwd+                        Irreducible -> panic "result not reducible"++----------------------------------------------------------------++-- | Split one or more nodes of the given graph, which must be+-- irreducible.++nodeSplit :: GraphWithDominators CmmNode+          -> UniqSM (GraphWithDominators CmmNode)+nodeSplit gwd =+    graphWithDominators <$> inflate (g_entry g) <$> runNullCollapse collapsed+  where g = gwd_graph gwd+        collapsed :: NullCollapseViz (Gr CmmSuper ())+        collapsed = collapseInductiveGraph (cgraphOfCmm g)++type CGraph = Gr CmmSuper ()++-- | Turn a collapsed supernode back into a control-flow graph+inflate :: Label -> CGraph -> CmmGraph+inflate entry cg = CmmGraph entry graph+  where graph = GMany NothingO body NothingO+        body :: LabelMap CmmBlock+        body = foldl (\map block -> mapInsert (entryLabel block) block map) mapEmpty $+               blocks super+        super = case labNodes cg of+                  [(_, s)] -> s+                  _ -> panic "graph given to `inflate` is not singleton"+++-- | Convert a `CmmGraph` into an inductive graph.+-- (The function coalesces duplicate edges into a single edge.)+cgraphOfCmm :: CmmGraph -> CGraph+cgraphOfCmm g = foldl' addSuccEdges (mkGraph cnodes []) blocks+   where blocks = zip [0..] $ revPostorderFrom (graphMap g) (g_entry g)+         cnodes = [(k, super block) | (k, block) <- blocks]+          where super block = Nodes (entryLabel block) (Seq.singleton block)+         labelNumber = \lbl -> fromJust $ mapLookup lbl numbers+             where numbers :: LabelMap Int+                   numbers = mapFromList $ map swap blocks+                   swap (k, block) = (entryLabel block, k)+         addSuccEdges :: CGraph -> (Node, CmmBlock) -> CGraph+         addSuccEdges graph (k, block) =+             insEdges [(k, labelNumber lbl, ()) | lbl <- nub $ successors block] graph+{-+Note [Reducibility resources]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++*Flow Analysis of Computer Programs.* Matthew S. Hecht North Holland, 1977.+Available to borrow from archive.org.++Matthew S. Hecht and Jeffrey D. Ullman (1972).+Flow Graph Reducibility. SIAM J. Comput., 1(2), 188–202.+https://doi.org/10.1137/0201014++Johan Janssen and Henk Corporaal. 1997. Making graphs reducible with+controlled node splitting. ACM TOPLAS 19, 6 (Nov. 1997),+1031–1052. DOI:https://doi.org/10.1145/267959.269971++Sebastian Unger and Frank Mueller. 2002. Handling irreducible loops:+optimized node splitting versus DJ-graphs. ACM TOPLAS 24, 4 (July+2002), 299–333. https://doi.org/10.1145/567097.567098.  (This one+contains the most detailed account of how the Hecht/Ullman algorithm+is used to modify an actual control-flow graph.  But still not much detail.)++https://rgrig.blogspot.com/2009/10/dtfloatleftclearleft-summary-of-some.html+ (Nice summary of useful facts)++-}++++type Seq = Seq.Seq++-- | A "supernode" contains a single-entry, multiple-exit, reducible subgraph.+-- The entry point is the given label, and the block with that label+-- dominates all the other blocks in the supernode.  When an entire+-- graph is collapsed into a single supernode, the graph is reducible.+-- More detail can be found in "GHC.Data.Graph.Collapse".++data CmmSuper+    = Nodes { label :: Label+            , blocks :: Seq CmmBlock+            }++instance Semigroup CmmSuper where+  s <> s' = Nodes (label s) (blocks s <> blocks s')++instance PureSupernode CmmSuper where+  superLabel = label+  mapLabels = changeLabels++instance Supernode CmmSuper NullCollapseViz where+  freshen s = liftUniqSM $ relabel s+++-- | Return all labels defined within a supernode.+definedLabels :: CmmSuper -> Seq Label+definedLabels = fmap entryLabel . blocks++++-- | Map the given function over every use and definition of a label+-- in the given supernode.+changeLabels :: (Label -> Label) -> (CmmSuper -> CmmSuper)+changeLabels f (Nodes l blocks) = Nodes (f l) (fmap (changeBlockLabels f) blocks)++-- | Map the given function over every use and definition of a label+-- in the given block.+changeBlockLabels :: (Label -> Label) -> CmmBlock -> CmmBlock+changeBlockLabels f block = blockJoin entry' middle exit'+  where (entry, middle, exit) = blockSplit block+        entry' = let CmmEntry l scope = entry+                 in  CmmEntry (f l) scope+        exit' = case exit of+                  -- unclear why mapSuccessors doesn't touch these+                  CmmCall { cml_cont = Just l } -> exit { cml_cont = Just (f l) }+                  CmmForeignCall { succ = l } -> exit { succ = f l }+                  _ -> mapSuccessors f exit+++-- | Within the given supernode, replace every defined label (and all+-- of its uses) with a fresh label.++relabel :: CmmSuper -> UniqSM CmmSuper+relabel node = do+     finite_map <- foldM addPair mapEmpty $ definedLabels node+     return $ changeLabels (labelChanger finite_map) node+  where addPair :: LabelMap Label -> Label -> UniqSM (LabelMap Label)+        addPair map old = do new <- newBlockId+                             return $ mapInsert old new map+        labelChanger :: LabelMap Label -> (Label -> Label)+        labelChanger mapping = \lbl -> mapFindWithDefault lbl lbl mapping
compiler/GHC/Cmm/Utils.hs view
@@ -197,9 +197,9 @@  -- | We make a top-level decl for the embedded binary file, and return a label pointing to it mkFileEmbedLit-  :: CLabel -> FilePath -> (CmmLit, GenCmmDecl (GenCmmStatics raw) info stmt)-mkFileEmbedLit lbl path-  = (CmmLabel lbl, CmmData (Section ReadOnlyData lbl) (CmmStaticsRaw lbl [CmmFileEmbed path]))+  :: CLabel -> FilePath -> Int -> (CmmLit, GenCmmDecl (GenCmmStatics raw) info stmt)+mkFileEmbedLit lbl path len+  = (CmmLabel lbl, CmmData (Section ReadOnlyData lbl) (CmmStaticsRaw lbl [CmmFileEmbed path len]))   -- | Build a data-segment data block
compiler/GHC/CmmToAsm.hs view
@@ -15,8 +15,6 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE UnboxedTuples #-} -{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}- -- | Native code generator -- -- The native-code generator has machine-independent and@@ -83,6 +81,7 @@ import qualified GHC.CmmToAsm.X86   as X86 import qualified GHC.CmmToAsm.PPC   as PPC import qualified GHC.CmmToAsm.AArch64 as AArch64+import qualified GHC.CmmToAsm.Wasm as Wasm32  import GHC.CmmToAsm.Reg.Liveness import qualified GHC.CmmToAsm.Reg.Linear                as Linear@@ -125,7 +124,6 @@ import GHC.Utils.Misc import GHC.Utils.Logger -import qualified GHC.Utils.Ppr as Pretty import GHC.Utils.BufHandle import GHC.Utils.Outputable as Outputable import GHC.Utils.Panic@@ -145,6 +143,7 @@ import Data.Ord         ( comparing ) import Control.Monad import System.IO+import System.Directory ( getCurrentDirectory )  -------------------- nativeCodeGen :: forall a . Logger -> NCGConfig -> ModLocation -> Handle -> UniqSupply@@ -169,6 +168,7 @@       ArchRISCV64   -> panic "nativeCodeGen: No NCG for RISCV64"       ArchUnknown   -> panic "nativeCodeGen: No NCG for unknown arch"       ArchJavaScript-> panic "nativeCodeGen: No NCG for JavaScript"+      ArchWasm32    -> Wasm32.ncgWasm platform us modLoc h cmms  -- | Data accumulated during code generation. Mostly about statistics, -- but also collects debug data for DWARF generation.@@ -242,16 +242,17 @@                 -> UniqSupply                 -> NativeGenAcc statics instr                 -> IO UniqSupply-finishNativeGen logger config modLoc bufh@(BufHandle _ _ h) us ngs+finishNativeGen logger config modLoc bufh us ngs  = withTimingSilent logger (text "NCG") (`seq` ()) $ do         -- Write debug data and finish         us' <- if not (ncgDwarfEnabled config)                   then return us                   else do-                     (dwarf, us') <- dwarfGen config modLoc us (ngs_debug ngs)-                     emitNativeCode logger config bufh dwarf+                     compPath <- getCurrentDirectory+                     let (dwarf_h, us') = dwarfGen compPath config modLoc us (ngs_debug ngs)+                         (dwarf_s, _)   = dwarfGen compPath config modLoc us (ngs_debug ngs)+                     emitNativeCode logger config bufh dwarf_h dwarf_s                      return us'-        bFlush bufh          -- dump global NCG stats for graph coloring allocator         let stats = concat (ngs_colorStats ngs)@@ -284,8 +285,9 @@          -- write out the imports         let ctx = ncgAsmContext config-        printSDocLn ctx Pretty.LeftMode h-                $ makeImportsDoc config (concat (ngs_imports ngs))+        bPutHDoc bufh ctx $ makeImportsDoc config (concat (ngs_imports ngs))+        bFlush bufh+         return us'   where     dump_stats = logDumpFile logger (mkDumpStyle alwaysQualify)@@ -387,12 +389,17 @@         let newFileIds = sortBy (comparing snd) $                          nonDetEltsUFM $ fileIds' `minusUFM` fileIds             -- See Note [Unique Determinism and code generation]-            pprDecl (f,n) = text "\t.file " <> int n <+>-                            pprFilePathString (unpackFS f)+            pprDecl (f,n) = line $ text "\t.file " <> int n <+>+                                   pprFilePathString (unpackFS f) -        emitNativeCode logger config h $ vcat $-          map pprDecl newFileIds ++-          map (pprNatCmmDecl ncgImpl) native+        -- see Note [pprNatCmmDeclS and pprNatCmmDeclH] in GHC.CmmToAsm.Monad+        emitNativeCode logger config h+          (vcat $+           map pprDecl newFileIds +++           map (pprNatCmmDeclH ncgImpl) native)+          (vcat $+           map pprDecl newFileIds +++           map (pprNatCmmDeclS ncgImpl) native)          -- force evaluation all this stuff to avoid space leaks         let platform = ncgPlatform config@@ -415,11 +422,11 @@         go us' cmms ngs' (count + 1)  -emitNativeCode :: Logger -> NCGConfig -> BufHandle -> SDoc -> IO ()-emitNativeCode logger config h sdoc = do-+-- see Note [pprNatCmmDeclS and pprNatCmmDeclH] in GHC.CmmToAsm.Monad+emitNativeCode :: Logger -> NCGConfig -> BufHandle -> HDoc -> SDoc -> IO ()+emitNativeCode logger config h hdoc sdoc = do         let ctx = ncgAsmContext config-        {-# SCC "pprNativeCode" #-} bufLeftRenderSDoc ctx h sdoc+        {-# SCC "pprNativeCode" #-} bPutHDoc h ctx hdoc          -- dump native code         putDumpFileMaybe logger@@ -483,7 +490,7 @@          putDumpFileMaybe logger                 Opt_D_dump_asm_native "Native code" FormatASM-                (vcat $ map (pprNatCmmDecl ncgImpl) native)+                (vcat $ map (pprNatCmmDeclS ncgImpl) native)          maybeDumpCfg logger (Just nativeCfgWeights) "CFG Weights - Native" proc_name @@ -540,7 +547,7 @@                 putDumpFileMaybe logger                         Opt_D_dump_asm_regalloc "Registers allocated"                         FormatCMM-                        (vcat $ map (pprNatCmmDecl ncgImpl) alloced)+                        (vcat $ map (pprNatCmmDeclS ncgImpl) alloced)                  putDumpFileMaybe logger                         Opt_D_dump_asm_regalloc_stages "Build/spill stages"@@ -584,7 +591,7 @@                 putDumpFileMaybe logger                         Opt_D_dump_asm_regalloc "Registers allocated"                         FormatCMM-                        (vcat $ map (pprNatCmmDecl ncgImpl) alloced)+                        (vcat $ map (pprNatCmmDeclS ncgImpl) alloced)                  let mPprStats =                         if logHasDumpFlag logger Opt_D_dump_asm_stats@@ -736,7 +743,7 @@  -- | Build a doc for all the imports. ---makeImportsDoc :: NCGConfig -> [CLabel] -> SDoc+makeImportsDoc :: NCGConfig -> [CLabel] -> HDoc makeImportsDoc config imports  = dyld_stubs imports             $$@@ -744,7 +751,7 @@             -- dead-stripping of code and data on a per-symbol basis.             -- There's a hack to make this work in PprMach.pprNatCmmDecl.             (if platformHasSubsectionsViaSymbols platform-             then text ".subsections_via_symbols"+             then line $ text ".subsections_via_symbols"              else Outputable.empty)             $$                 -- On recent GNU ELF systems one can mark an object file@@ -754,14 +761,14 @@                 -- security. GHC generated code does not need an executable                 -- stack so add the note in:             (if platformHasGnuNonexecStack platform-             then text ".section .note.GNU-stack,\"\"," <> sectionType platform "progbits"+             then line $ text ".section .note.GNU-stack,\"\"," <> sectionType platform "progbits"              else Outputable.empty)             $$                 -- And just because every other compiler does, let's stick in                 -- an identifier directive: .ident "GHC x.y.z"             (if platformHasIdentDirective platform              then let compilerIdent = text "GHC" <+> text cProjectVersion-                   in text ".ident" <+> doubleQuotes compilerIdent+                   in line $ text ".ident" <+> doubleQuotes compilerIdent              else Outputable.empty)   where@@ -769,7 +776,7 @@          -- Generate "symbol stubs" for all external symbols that might         -- come from a dynamic library.-        dyld_stubs :: [CLabel] -> SDoc+        dyld_stubs :: [CLabel] -> HDoc         -- (Hack) sometimes two Labels pretty-print the same, but have         -- different uniques; so we compare their text versions...         dyld_stubs imps@@ -798,7 +805,7 @@ generateJumpTables ncgImpl xs = concatMap f xs     where f p@(CmmProc _ _ _ (ListGraph xs)) = p : concatMap g xs           f p = [p]-          g (BasicBlock _ xs) = catMaybes (map (generateJumpTableForInstr ncgImpl) xs)+          g (BasicBlock _ xs) = mapMaybe (generateJumpTableForInstr ncgImpl) xs  -- ----------------------------------------------------------------------------- -- Shortcut branches
compiler/GHC/CmmToAsm/AArch64.hs view
@@ -11,6 +11,7 @@ import GHC.CmmToAsm.Monad import GHC.CmmToAsm.Config import GHC.CmmToAsm.Types+import GHC.Utils.Outputable (ftext)  import qualified GHC.CmmToAsm.AArch64.Instr   as AArch64 import qualified GHC.CmmToAsm.AArch64.Ppr     as AArch64@@ -28,7 +29,8 @@        ,canShortcut               = AArch64.canShortcut        ,shortcutStatics           = AArch64.shortcutStatics        ,shortcutJump              = AArch64.shortcutJump-       ,pprNatCmmDecl             = AArch64.pprNatCmmDecl config+       ,pprNatCmmDeclS            = AArch64.pprNatCmmDecl config+       ,pprNatCmmDeclH            = AArch64.pprNatCmmDecl config        ,maxSpillSlots             = AArch64.maxSpillSlots config        ,allocatableRegs           = AArch64.allocatableRegs platform        ,ncgAllocMoreStack         = AArch64.allocMoreStack platform@@ -55,5 +57,5 @@         mkJumpInstr             = AArch64.mkJumpInstr         mkStackAllocInstr       = AArch64.mkStackAllocInstr         mkStackDeallocInstr     = AArch64.mkStackDeallocInstr-        mkComment               = pure . AArch64.COMMENT+        mkComment               = pure . AArch64.COMMENT . ftext         pprInstr                = AArch64.pprInstr
compiler/GHC/CmmToAsm/AArch64/CodeGen.hs view
@@ -910,7 +910,6 @@                       intOp True w (\d x y -> toOL [ SDIV t x y, MSUB d t y x ])          -- Unsigned multiply/divide-        MO_U_MulMayOflo _w -> unsupportedP plat expr         MO_U_Quot w -> intOp False w (\d x y -> unitOL $ UDIV d x y)         MO_U_Rem w  -> withTempIntReg w $ \t ->                        intOp False w (\d x y -> toOL [ UDIV t x y, MSUB d t y x ])@@ -962,9 +961,6 @@       -> pprPanic "getRegister' (variadic CmmMachOp): " (pdoc plat expr)    where-    unsupportedP :: OutputableP env a => env -> a -> b-    unsupportedP platform op = pprPanic "Unsupported op:" (pdoc platform op)-     isNbitEncodeable :: Int -> Integer -> Bool     isNbitEncodeable n i = let shift = n - 1 in (-1 `shiftL` shift) <= i && i < (1 `shiftL` shift)     -- This needs to check if n can be encoded as a bitmask immediate:
compiler/GHC/CmmToAsm/AArch64/Ppr.hs view
@@ -29,12 +29,12 @@  import GHC.Utils.Panic -pprProcAlignment :: NCGConfig -> SDoc+pprProcAlignment :: IsDoc doc => NCGConfig -> doc pprProcAlignment config = maybe empty (pprAlign platform . mkAlignment) (ncgProcAlignment config)    where       platform = ncgPlatform config -pprNatCmmDecl :: NCGConfig -> NatCmmDecl RawCmmStatics Instr -> SDoc+pprNatCmmDecl :: IsDoc doc => NCGConfig -> NatCmmDecl RawCmmStatics Instr -> doc pprNatCmmDecl config (CmmData section dats) =   pprSectionAlign config section $$ pprDatas config dats @@ -50,42 +50,45 @@         pprLabel platform lbl $$ -- blocks guaranteed not null, so label needed         vcat (map (pprBasicBlock config top_info) blocks) $$         (if ncgDwarfEnabled config-         then pprAsmLabel platform (mkAsmTempEndLabel lbl) <> char ':' else empty) $$+         then line (pprAsmLabel platform (mkAsmTempEndLabel lbl) <> char ':') else empty) $$         pprSizeDecl platform lbl      Just (CmmStaticsRaw info_lbl _) ->       pprSectionAlign config (Section Text info_lbl) $$       -- pprProcAlignment config $$       (if platformHasSubsectionsViaSymbols platform-          then pprAsmLabel platform (mkDeadStripPreventer info_lbl) <> char ':'+          then line (pprAsmLabel platform (mkDeadStripPreventer info_lbl) <> char ':')           else empty) $$       vcat (map (pprBasicBlock config top_info) blocks) $$       -- above: Even the first block gets a label, because with branch-chain       -- elimination, it might be the target of a goto.       (if platformHasSubsectionsViaSymbols platform        then -- See Note [Subsections Via Symbols]-                text "\t.long "+                line+              $ text "\t.long "             <+> pprAsmLabel platform info_lbl             <+> char '-'             <+> pprAsmLabel platform (mkDeadStripPreventer info_lbl)        else empty) $$       pprSizeDecl platform info_lbl+{-# SPECIALIZE pprNatCmmDecl :: NCGConfig -> NatCmmDecl RawCmmStatics Instr -> SDoc #-}+{-# SPECIALIZE pprNatCmmDecl :: NCGConfig -> NatCmmDecl RawCmmStatics Instr -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable -pprLabel :: Platform -> CLabel -> SDoc+pprLabel :: IsDoc doc => Platform -> CLabel -> doc pprLabel platform lbl =    pprGloblDecl platform lbl    $$ pprTypeDecl platform lbl-   $$ (pprAsmLabel platform lbl <> char ':')+   $$ line (pprAsmLabel platform lbl <> char ':') -pprAlign :: Platform -> Alignment -> SDoc+pprAlign :: IsDoc doc => Platform -> Alignment -> doc pprAlign _platform alignment-        = text "\t.balign " <> int (alignmentBytes alignment)+        = line $ text "\t.balign " <> int (alignmentBytes alignment)  -- | Print appropriate alignment for the given section type.-pprAlignForSection :: Platform -> SectionType -> SDoc+pprAlignForSection :: IsDoc doc => Platform -> SectionType -> doc pprAlignForSection _platform _seg     -- .balign is stable, whereas .align is platform dependent.-    = text "\t.balign 8" --  always 8+    = line (text "\t.balign 8") --  always 8  -- | Print section header and appropriate alignment for that section. --@@ -94,28 +97,28 @@ --     .section .text --     .balign 8 ---pprSectionAlign :: NCGConfig -> Section -> SDoc+pprSectionAlign :: IsDoc doc => NCGConfig -> Section -> doc pprSectionAlign _config (Section (OtherSection _) _) =      panic "AArch64.Ppr.pprSectionAlign: unknown section" pprSectionAlign config sec@(Section seg _) =-    pprSectionHeader config sec+    line (pprSectionHeader config sec)     $$ pprAlignForSection (ncgPlatform config) seg  -- | Output the ELF .size directive.-pprSizeDecl :: Platform -> CLabel -> SDoc+pprSizeDecl :: IsDoc doc => Platform -> CLabel -> doc pprSizeDecl platform lbl  = if osElfTarget (platformOS platform)-   then text "\t.size" <+> pprAsmLabel platform lbl <> text ", .-" <> pprAsmLabel platform lbl+   then line (text "\t.size" <+> pprAsmLabel platform lbl <> text ", .-" <> pprAsmLabel platform lbl)    else empty -pprBasicBlock :: NCGConfig -> LabelMap RawCmmStatics -> NatBasicBlock Instr-              -> SDoc+pprBasicBlock :: IsDoc doc => NCGConfig -> LabelMap RawCmmStatics -> NatBasicBlock Instr+              -> doc pprBasicBlock config info_env (BasicBlock blockid instrs)   = maybe_infotable $     pprLabel platform asmLbl $$     vcat (map (pprInstr platform) (id {-detectTrivialDeadlock-} optInstrs)) $$     (if  ncgDwarfEnabled config-      then pprAsmLabel platform (mkAsmTempEndLabel asmLbl) <> char ':'+      then line (pprAsmLabel platform (mkAsmTempEndLabel asmLbl) <> char ':')       else empty     )   where@@ -135,7 +138,7 @@            pprLabel platform info_lbl $$            c $$            (if ncgDwarfEnabled config-             then pprAsmLabel platform (mkAsmTempEndLabel info_lbl) <> char ':'+             then line (pprAsmLabel platform (mkAsmTempEndLabel info_lbl) <> char ':')              else empty)     -- Make sure the info table has the right .loc for the block     -- coming right after it. See Note [Info Offset]@@ -143,7 +146,7 @@       (l@LOCATION{} : _) -> pprInstr platform l       _other             -> empty -pprDatas :: NCGConfig -> RawCmmStatics -> SDoc+pprDatas :: IsDoc doc => NCGConfig -> RawCmmStatics -> doc -- See Note [emit-time elimination of static indirections] in "GHC.Cmm.CLabel". pprDatas config (CmmStaticsRaw alias [CmmStaticLit (CmmLabel lbl), CmmStaticLit ind, _, _])   | lbl == mkIndStaticInfoLabel@@ -153,29 +156,29 @@   , Just ind' <- labelInd ind   , alias `mayRedirectTo` ind'   = pprGloblDecl (ncgPlatform config) alias-    $$ text ".equiv" <+> pprAsmLabel (ncgPlatform config) alias <> comma <> pprAsmLabel (ncgPlatform config) ind'+    $$ line (text ".equiv" <+> pprAsmLabel (ncgPlatform config) alias <> comma <> pprAsmLabel (ncgPlatform config) ind')  pprDatas config (CmmStaticsRaw lbl dats)   = vcat (pprLabel platform lbl : map (pprData config) dats)    where       platform = ncgPlatform config -pprData :: NCGConfig -> CmmStatic -> SDoc-pprData _config (CmmString str) = pprString str-pprData _config (CmmFileEmbed path) = pprFileEmbed path+pprData :: IsDoc doc => NCGConfig -> CmmStatic -> doc+pprData _config (CmmString str) = line (pprString str)+pprData _config (CmmFileEmbed path _) = line (pprFileEmbed path)  pprData config (CmmUninitialised bytes)- = let platform = ncgPlatform config-   in if platformOS platform == OSDarwin-         then text ".space " <> int bytes-         else text ".skip "  <> int bytes+ = line $ let platform = ncgPlatform config+          in if platformOS platform == OSDarwin+                then text ".space " <> int bytes+                else text ".skip "  <> int bytes  pprData config (CmmStaticLit lit) = pprDataItem config lit -pprGloblDecl :: Platform -> CLabel -> SDoc+pprGloblDecl :: IsDoc doc => Platform -> CLabel -> doc pprGloblDecl platform lbl   | not (externallyVisibleCLabel lbl) = empty-  | otherwise = text "\t.globl " <> pprAsmLabel platform lbl+  | otherwise = line (text "\t.globl " <> pprAsmLabel platform lbl)  -- Note [Always use objects for info tables] -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@@ -187,7 +190,7 @@ -- -- Fun fact: The LLVMMangler exists to patch this issue su on the LLVM side as -- well.-pprLabelType' :: Platform -> CLabel -> SDoc+pprLabelType' :: IsLine doc => Platform -> CLabel -> doc pprLabelType' platform lbl =   if isCFunctionLabel lbl || functionOkInfoTable then     text "@function"@@ -198,15 +201,15 @@       isInfoTableLabel lbl && not (isCmmInfoTableLabel lbl) && not (isConInfoTableLabel lbl)  -- this is called pprTypeAndSizeDecl in PPC.Ppr-pprTypeDecl :: Platform -> CLabel -> SDoc+pprTypeDecl :: IsDoc doc => Platform -> CLabel -> doc pprTypeDecl platform lbl     = if osElfTarget (platformOS platform) && externallyVisibleCLabel lbl-      then text ".type " <> pprAsmLabel platform lbl <> text ", " <> pprLabelType' platform lbl+      then line (text ".type " <> pprAsmLabel platform lbl <> text ", " <> pprLabelType' platform lbl)       else empty -pprDataItem :: NCGConfig -> CmmLit -> SDoc+pprDataItem :: IsDoc doc => NCGConfig -> CmmLit -> doc pprDataItem config lit-  = vcat (ppr_item (cmmTypeFormat $ cmmLitType platform lit) lit)+  = lines_ (ppr_item (cmmTypeFormat $ cmmLitType platform lit) lit)     where         platform = ncgPlatform config @@ -227,12 +230,12 @@          ppr_item _ _ = pprPanic "pprDataItem:ppr_item" (text $ show lit) -pprImm :: Platform -> Imm -> SDoc+pprImm :: IsLine doc => Platform -> Imm -> doc pprImm _ (ImmInt i)     = int i pprImm _ (ImmInteger i) = integer i pprImm p (ImmCLbl l)    = pprAsmLabel p l pprImm p (ImmIndex l i) = pprAsmLabel p l <> char '+' <> int i-pprImm _ (ImmLit s)     = text s+pprImm _ (ImmLit s)     = ftext s  -- TODO: See pprIm below for why this is a bad idea! pprImm _ (ImmFloat f)@@ -257,7 +260,7 @@ asmMultilineComment :: SDoc -> SDoc asmMultilineComment c = whenPprDebug $ text "/*" $+$ c $+$ text "*/" -pprIm :: Platform -> Imm -> SDoc+pprIm :: IsLine doc => Platform -> Imm -> doc pprIm platform im = case im of   ImmInt i     -> char '#' <> int i   ImmInteger i -> char '#' <> integer i@@ -283,7 +286,7 @@   ImmIndex l o -> text "[=" <> pprAsmLabel platform l <> comma <+> char '#' <> int o <> char ']'   _            -> panic "AArch64.pprIm" -pprExt :: ExtMode -> SDoc+pprExt :: IsLine doc => ExtMode -> doc pprExt EUXTB = text "uxtb" pprExt EUXTH = text "uxth" pprExt EUXTW = text "uxtw"@@ -293,13 +296,13 @@ pprExt ESXTW = text "sxtw" pprExt ESXTX = text "sxtx" -pprShift :: ShiftMode -> SDoc+pprShift :: IsLine doc => ShiftMode -> doc pprShift SLSL = text "lsl" pprShift SLSR = text "lsr" pprShift SASR = text "asr" pprShift SROR = text "ror" -pprOp :: Platform -> Operand -> SDoc+pprOp :: IsLine doc => Platform -> Operand -> doc pprOp plat op = case op of   OpReg w r           -> pprReg w r   OpRegExt w r x 0 -> pprReg w r <> comma <+> pprExt x@@ -312,7 +315,7 @@   OpAddr (AddrRegImm r1 im) -> char '[' <+> pprReg W64 r1 <> comma <+> pprImm plat im <+> char ']'   OpAddr (AddrReg r1)       -> char '[' <+> pprReg W64 r1 <+> char ']' -pprReg :: Width -> Reg -> SDoc+pprReg :: forall doc. IsLine doc => Width -> Reg -> doc pprReg w r = case r of   RegReal    (RealRegSingle i) -> ppr_reg_no w i   -- virtual regs should not show up, but this is helpful for debugging.@@ -322,7 +325,7 @@   _                            -> pprPanic "AArch64.pprReg" (text $ show r)    where-    ppr_reg_no :: Width -> Int -> SDoc+    ppr_reg_no :: Width -> Int -> doc     ppr_reg_no w 31          | w == W64 = text "sp"          | w == W32 = text "wsp"@@ -351,24 +354,27 @@ isFloatOp (OpReg _ (RegVirtual (VirtualRegD _))) = True isFloatOp _ = False -pprInstr :: Platform -> Instr -> SDoc+pprInstr :: IsDoc doc => Platform -> Instr -> doc pprInstr platform instr = case instr of   -- Meta Instructions ----------------------------------------------------------  COMMENT s  -> asmComment s-  MULTILINE_COMMENT s -> asmMultilineComment s-  ANN d i -> pprInstr platform i <+> asmDoubleslashComment d-  LOCATION file line col _name-    -> text "\t.loc" <+> ppr file <+> ppr line <+> ppr col-  DELTA d    -> asmComment $ text ("\tdelta = " ++ show d)+  -- see Note [dualLine and dualDoc] in GHC.Utils.Outputable+  COMMENT s  -> dualDoc (asmComment s) empty+  MULTILINE_COMMENT s -> dualDoc (asmMultilineComment s) empty+  ANN d i -> dualDoc (pprInstr platform i <+> asmDoubleslashComment d) (pprInstr platform i)++  LOCATION file line' col _name+    -> line (text "\t.loc" <+> int file <+> int line' <+> int col)+  DELTA d   -> dualDoc (asmComment $ text "\tdelta = " <> int d) empty+               -- see Note [dualLine and dualDoc] in GHC.Utils.Outputable   NEWBLOCK _ -> panic "PprInstr: NEWBLOCK"   LDATA _ _  -> panic "pprInstr: LDATA"    -- Pseudo Instructions ------------------------------------------------------- -  PUSH_STACK_FRAME -> text "\tstp x29, x30, [sp, #-16]!"-                   $$ text "\tmov x29, sp"+  PUSH_STACK_FRAME -> lines_ [text "\tstp x29, x30, [sp, #-16]!",+                              text "\tmov x29, sp"] -  POP_STACK_FRAME -> text "\tldp x29, x30, [sp], #16"+  POP_STACK_FRAME -> line $ text "\tldp x29, x30, [sp], #16"   -- ===========================================================================   -- AArch64 Instruction Set   -- 1. Arithmetic Instructions ------------------------------------------------@@ -430,28 +436,28 @@    -- 4. Branch Instructions ----------------------------------------------------   J t            -> pprInstr platform (B t)-  B (TBlock bid) -> text "\tb" <+> pprAsmLabel platform (mkLocalBlockLabel (getUnique bid))-  B (TLabel lbl) -> text "\tb" <+> pprAsmLabel platform lbl-  B (TReg r)     -> text "\tbr" <+> pprReg W64 r+  B (TBlock bid) -> line $ text "\tb" <+> pprAsmLabel platform (mkLocalBlockLabel (getUnique bid))+  B (TLabel lbl) -> line $ text "\tb" <+> pprAsmLabel platform lbl+  B (TReg r)     -> line $ text "\tbr" <+> pprReg W64 r -  BL (TBlock bid) _ _ -> text "\tbl" <+> pprAsmLabel platform (mkLocalBlockLabel (getUnique bid))-  BL (TLabel lbl) _ _ -> text "\tbl" <+> pprAsmLabel platform lbl-  BL (TReg r)     _ _ -> text "\tblr" <+> pprReg W64 r+  BL (TBlock bid) _ _ -> line $ text "\tbl" <+> pprAsmLabel platform (mkLocalBlockLabel (getUnique bid))+  BL (TLabel lbl) _ _ -> line $ text "\tbl" <+> pprAsmLabel platform lbl+  BL (TReg r)     _ _ -> line $ text "\tblr" <+> pprReg W64 r -  BCOND c (TBlock bid) -> text "\t" <> pprBcond c <+> pprAsmLabel platform (mkLocalBlockLabel (getUnique bid))-  BCOND c (TLabel lbl) -> text "\t" <> pprBcond c <+> pprAsmLabel platform lbl+  BCOND c (TBlock bid) -> line $ text "\t" <> pprBcond c <+> pprAsmLabel platform (mkLocalBlockLabel (getUnique bid))+  BCOND c (TLabel lbl) -> line $ text "\t" <> pprBcond c <+> pprAsmLabel platform lbl   BCOND _ (TReg _)     -> panic "AArch64.ppr: No conditional branching to registers!"    -- 5. Atomic Instructions ----------------------------------------------------   -- 6. Conditional Instructions ------------------------------------------------  CSET o c  -> text "\tcset" <+> pprOp platform o <> comma <+> pprCond c+  CSET o c  -> line $ text "\tcset" <+> pprOp platform o <> comma <+> pprCond c -  CBZ o (TBlock bid) -> text "\tcbz" <+> pprOp platform o <> comma <+> pprAsmLabel platform (mkLocalBlockLabel (getUnique bid))-  CBZ o (TLabel lbl) -> text "\tcbz" <+> pprOp platform o <> comma <+> pprAsmLabel platform lbl+  CBZ o (TBlock bid) -> line $ text "\tcbz" <+> pprOp platform o <> comma <+> pprAsmLabel platform (mkLocalBlockLabel (getUnique bid))+  CBZ o (TLabel lbl) -> line $ text "\tcbz" <+> pprOp platform o <> comma <+> pprAsmLabel platform lbl   CBZ _ (TReg _)     -> panic "AArch64.ppr: No conditional (cbz) branching to registers!" -  CBNZ o (TBlock bid) -> text "\tcbnz" <+> pprOp platform o <> comma <+> pprAsmLabel platform (mkLocalBlockLabel (getUnique bid))-  CBNZ o (TLabel lbl) -> text "\tcbnz" <+> pprOp platform o <> comma <+> pprAsmLabel platform lbl+  CBNZ o (TBlock bid) -> line $ text "\tcbnz" <+> pprOp platform o <> comma <+> pprAsmLabel platform (mkLocalBlockLabel (getUnique bid))+  CBNZ o (TLabel lbl) -> line $ text "\tcbnz" <+> pprOp platform o <> comma <+> pprAsmLabel platform lbl   CBNZ _ (TReg _)     -> panic "AArch64.ppr: No conditional (cbnz) branching to registers!"    -- 7. Load and Store Instructions --------------------------------------------@@ -532,23 +538,23 @@   LDP _f o1 o2 o3 -> op3 (text "\tldp") o1 o2 o3    -- 8. Synchronization Instructions --------------------------------------------  DMBSY -> text "\tdmb sy"+  DMBSY -> line $ text "\tdmb sy"   -- 9. Floating Point Instructions --------------------------------------------   FCVT o1 o2 -> op2 (text "\tfcvt") o1 o2   SCVTF o1 o2 -> op2 (text "\tscvtf") o1 o2   FCVTZS o1 o2 -> op2 (text "\tfcvtzs") o1 o2   FABS o1 o2 -> op2 (text "\tfabs") o1 o2- where op2 op o1 o2 = op <+> pprOp platform o1 <> comma <+> pprOp platform o2-       op3 op o1 o2 o3 = op <+> pprOp platform o1 <> comma <+> pprOp platform o2 <> comma <+> pprOp platform o3-       op4 op o1 o2 o3 o4 = op <+> pprOp platform o1 <> comma <+> pprOp platform o2 <> comma <+> pprOp platform o3 <> comma <+> pprOp platform o4-       op_ldr o1 rest = text "\tldr" <+> pprOp platform o1 <> comma <+> text "[" <> pprOp platform o1 <> comma <+> rest <> text "]"-       op_adrp o1 rest = text "\tadrp" <+> pprOp platform o1 <> comma <+> rest-       op_add o1 rest = text "\tadd" <+> pprOp platform o1 <> comma <+> pprOp platform o1 <> comma <+> rest+ where op2 op o1 o2        = line $ op <+> pprOp platform o1 <> comma <+> pprOp platform o2+       op3 op o1 o2 o3     = line $ op <+> pprOp platform o1 <> comma <+> pprOp platform o2 <> comma <+> pprOp platform o3+       op4 op o1 o2 o3 o4  = line $ op <+> pprOp platform o1 <> comma <+> pprOp platform o2 <> comma <+> pprOp platform o3 <> comma <+> pprOp platform o4+       op_ldr o1 rest      = line $ text "\tldr" <+> pprOp platform o1 <> comma <+> text "[" <> pprOp platform o1 <> comma <+> rest <> text "]"+       op_adrp o1 rest     = line $ text "\tadrp" <+> pprOp platform o1 <> comma <+> rest+       op_add o1 rest      = line $ text "\tadd" <+> pprOp platform o1 <> comma <+> pprOp platform o1 <> comma <+> rest -pprBcond :: Cond -> SDoc+pprBcond :: IsLine doc => Cond -> doc pprBcond c = text "b." <> pprCond c -pprCond :: Cond -> SDoc+pprCond :: IsLine doc => Cond -> doc pprCond c = case c of   ALWAYS -> text "al" -- Always   EQ     -> text "eq" -- Equal
compiler/GHC/CmmToAsm/AArch64/Regs.hs view
@@ -2,6 +2,7 @@ module GHC.CmmToAsm.AArch64.Regs where  import GHC.Prelude+import GHC.Data.FastString  import GHC.Platform.Reg import GHC.Platform.Reg.Class@@ -59,7 +60,7 @@   = ImmInt      Int   | ImmInteger  Integer     -- Sigh.   | ImmCLbl     CLabel      -- AbstractC Label (with baggage)-  | ImmLit      String+  | ImmLit      FastString   | ImmIndex    CLabel Int   | ImmFloat    Rational   | ImmDouble   Rational@@ -67,7 +68,7 @@   | ImmConstantDiff Imm Imm   deriving (Eq, Show) -strImmLit :: String -> Imm+strImmLit :: FastString -> Imm strImmLit s = ImmLit s  
compiler/GHC/CmmToAsm/BlockLayout.hs view
@@ -35,7 +35,6 @@ import GHC.Data.List.SetOps (removeDups) import GHC.Data.OrdList -import GHC.Utils.Trace import GHC.Utils.Outputable import GHC.Utils.Panic import GHC.Utils.Panic.Plain@@ -658,7 +657,7 @@ sequenceChain _info _weights    [x] = [x] sequenceChain  info weights     blocks@((BasicBlock entry _):_) =     let directEdges :: [CfgEdge]-        directEdges = sortBy (flip compare) $ catMaybes . map relevantWeight $ (infoEdgeList weights)+        directEdges = sortBy (flip compare) $ mapMaybe relevantWeight (infoEdgeList weights)           where             -- Apply modifiers to turn edge frequencies into useable weights             -- for computing code layout.
compiler/GHC/CmmToAsm/Dwarf.hs view
@@ -26,50 +26,47 @@ import Data.Ord         ( comparing ) import qualified Data.Map as Map import System.FilePath-import System.Directory ( getCurrentDirectory )  import qualified GHC.Cmm.Dataflow.Label as H import qualified GHC.Cmm.Dataflow.Collections as H  -- | Generate DWARF/debug information-dwarfGen :: NCGConfig -> ModLocation -> UniqSupply -> [DebugBlock]-            -> IO (SDoc, UniqSupply)-dwarfGen _      _      us []     = return (empty, us)-dwarfGen config modLoc us blocks = do+dwarfGen :: IsDoc doc => String -> NCGConfig -> ModLocation -> UniqSupply -> [DebugBlock]+            -> (doc, UniqSupply)+dwarfGen _        _      _      us []     = (empty, us)+dwarfGen compPath config modLoc us blocks =   let platform = ncgPlatform config -  -- Convert debug data structures to DWARF info records-  let procs = debugSplitProcs blocks+      -- Convert debug data structures to DWARF info records+      procs = debugSplitProcs blocks       stripBlocks dbg         | ncgDwarfStripBlockInfo config = dbg { dblBlocks = [] }         | otherwise                     = dbg-  compPath <- getCurrentDirectory-  let lowLabel = dblCLabel $ head procs+      lowLabel = dblCLabel $ head procs       highLabel = mkAsmTempProcEndLabel $ dblCLabel $ last procs       dwarfUnit = DwarfCompileUnit         { dwChildren = map (procToDwarf config) (map stripBlocks procs)         , dwName = fromMaybe "" (ml_hs_file modLoc)         , dwCompDir = addTrailingPathSeparator compPath         , dwProducer = cProjectName ++ " " ++ cProjectVersion-        , dwLowLabel = pprAsmLabel platform lowLabel-        , dwHighLabel = pprAsmLabel platform highLabel-        , dwLineLabel = dwarfLineLabel+        , dwLowLabel = lowLabel+        , dwHighLabel = highLabel         } -  -- Check whether we have any source code information, so we do not-  -- end up writing a pointer to an empty .debug_line section-  -- (dsymutil on Mac Os gets confused by this).-  let haveSrcIn blk = isJust (dblSourceTick blk) && isJust (dblPosition blk)+      -- Check whether we have any source code information, so we do not+      -- end up writing a pointer to an empty .debug_line section+      -- (dsymutil on Mac Os gets confused by this).+      haveSrcIn blk = isJust (dblSourceTick blk) && isJust (dblPosition blk)                       || any haveSrcIn (dblBlocks blk)       haveSrc = any haveSrcIn procs    -- .debug_abbrev section: Declare the format we're using-  let abbrevSct = pprAbbrevDecls platform haveSrc+      abbrevSct = pprAbbrevDecls platform haveSrc    -- .debug_info section: Information records on procedures and blocks-  let -- unique to identify start and end compilation unit .debug_inf+      -- unique to identify start and end compilation unit .debug_inf       (unitU, us') = takeUniqFromSupply us-      infoSct = vcat [ dwarfInfoLabel <> colon+      infoSct = vcat [ line (dwarfInfoLabel <> colon)                      , dwarfInfoSection platform                      , compileUnitHeader platform unitU                      , pprDwarfInfo platform haveSrc dwarfUnit@@ -78,21 +75,23 @@    -- .debug_line section: Generated mainly by the assembler, but we   -- need to label it-  let lineSct = dwarfLineSection platform $$-                dwarfLineLabel <> colon+      lineSct = dwarfLineSection platform $$+                line (dwarfLineLabel <> colon)    -- .debug_frame section: Information about the layout of the GHC stack-  let (framesU, us'') = takeUniqFromSupply us'+      (framesU, us'') = takeUniqFromSupply us'       frameSct = dwarfFrameSection platform $$-                 dwarfFrameLabel <> colon $$+                 line (dwarfFrameLabel <> colon) $$                  pprDwarfFrame platform (debugFrame framesU procs)    -- .aranges section: Information about the bounds of compilation units-  let aranges' | ncgSplitSections config = map mkDwarfARange procs+      aranges' | ncgSplitSections config = map mkDwarfARange procs                | otherwise               = [DwarfARange lowLabel highLabel]-  let aranges = dwarfARangesSection platform $$ pprDwarfARanges platform aranges' unitU+      aranges = dwarfARangesSection platform $$ pprDwarfARanges platform aranges' unitU -  return (infoSct $$ abbrevSct $$ lineSct $$ frameSct $$ aranges, us'')+  in (infoSct $$ abbrevSct $$ lineSct $$ frameSct $$ aranges, us'')+{-# SPECIALIZE dwarfGen :: String -> NCGConfig -> ModLocation -> UniqSupply -> [DebugBlock] -> (SDoc, UniqSupply) #-}+{-# SPECIALIZE dwarfGen :: String -> NCGConfig -> ModLocation -> UniqSupply -> [DebugBlock] -> (HDoc, UniqSupply) #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Build an address range entry for one proc. -- With split sections, each proc needs its own entry, since they may get@@ -106,24 +105,24 @@  -- | Header for a compilation unit, establishing global format -- parameters-compileUnitHeader :: Platform -> Unique -> SDoc+compileUnitHeader :: IsDoc doc => Platform -> Unique -> doc compileUnitHeader platform unitU =   let cuLabel = mkAsmTempLabel unitU  -- sits right before initialLength field       length = pprAsmLabel platform (mkAsmTempEndLabel cuLabel) <> char '-' <> pprAsmLabel platform cuLabel                <> text "-4"       -- length of initialLength field-  in vcat [ pprAsmLabel platform cuLabel <> colon-          , text "\t.long " <> length  -- compilation unit size+  in vcat [ line (pprAsmLabel platform cuLabel <> colon)+          , line (text "\t.long " <> length)  -- compilation unit size           , pprHalf 3                          -- DWARF version           , sectionOffset platform dwarfAbbrevLabel dwarfAbbrevLabel                                                -- abbrevs offset-          , text "\t.byte " <> ppr (platformWordSizeInBytes platform) -- word size+          , line (text "\t.byte " <> int (platformWordSizeInBytes platform)) -- word size           ]  -- | Compilation unit footer, mainly establishing size of debug sections-compileUnitFooter :: Platform -> Unique -> SDoc+compileUnitFooter :: IsDoc doc => Platform -> Unique -> doc compileUnitFooter platform unitU =   let cuEndLabel = mkAsmTempEndLabel $ mkAsmTempLabel unitU-  in pprAsmLabel platform cuEndLabel <> colon+  in line (pprAsmLabel platform cuEndLabel <> colon)  -- | Splits the blocks by procedures. In the result all nested blocks -- will come from the same procedure as the top-level block. See
compiler/GHC/CmmToAsm/Dwarf/Constants.hs view
@@ -144,17 +144,29 @@  -- * Dwarf section declarations dwarfInfoSection, dwarfAbbrevSection, dwarfLineSection,-  dwarfFrameSection, dwarfGhcSection, dwarfARangesSection :: Platform -> SDoc+  dwarfFrameSection, dwarfGhcSection, dwarfARangesSection :: IsDoc doc => Platform -> doc dwarfInfoSection    platform = dwarfSection platform "info" dwarfAbbrevSection  platform = dwarfSection platform "abbrev" dwarfLineSection    platform = dwarfSection platform "line" dwarfFrameSection   platform = dwarfSection platform "frame" dwarfGhcSection     platform = dwarfSection platform "ghc" dwarfARangesSection platform = dwarfSection platform "aranges"+{-# SPECIALIZE dwarfInfoSection :: Platform -> SDoc #-}+{-# SPECIALIZE dwarfInfoSection :: Platform -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable+{-# SPECIALIZE dwarfAbbrevSection :: Platform -> SDoc #-}+{-# SPECIALIZE dwarfAbbrevSection :: Platform -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable+{-# SPECIALIZE dwarfLineSection :: Platform -> SDoc #-}+{-# SPECIALIZE dwarfLineSection :: Platform -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable+{-# SPECIALIZE dwarfFrameSection :: Platform -> SDoc #-}+{-# SPECIALIZE dwarfFrameSection :: Platform -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable+{-# SPECIALIZE dwarfGhcSection :: Platform -> SDoc #-}+{-# SPECIALIZE dwarfGhcSection :: Platform -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable+{-# SPECIALIZE dwarfARangesSection :: Platform -> SDoc #-}+{-# SPECIALIZE dwarfARangesSection :: Platform -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable -dwarfSection :: Platform -> String -> SDoc+dwarfSection :: IsDoc doc => Platform -> String -> doc dwarfSection platform name =-  case platformOS platform of+  line $ case platformOS platform of     os | osElfTarget os        -> text "\t.section .debug_" <> text name <> text ",\"\","           <> sectionType platform "progbits"@@ -162,13 +174,24 @@        -> text "\t.section __DWARF,__debug_" <> text name <> text ",regular,debug"        | otherwise        -> text "\t.section .debug_" <> text name <> text ",\"dr\""+{-# SPECIALIZE dwarfSection :: Platform -> String -> SDoc #-}+{-# SPECIALIZE dwarfSection :: Platform -> String -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable + -- * Dwarf section labels-dwarfInfoLabel, dwarfAbbrevLabel, dwarfLineLabel, dwarfFrameLabel :: SDoc+dwarfInfoLabel, dwarfAbbrevLabel, dwarfLineLabel, dwarfFrameLabel :: IsLine doc => doc dwarfInfoLabel   = text ".Lsection_info" dwarfAbbrevLabel = text ".Lsection_abbrev" dwarfLineLabel   = text ".Lsection_line" dwarfFrameLabel  = text ".Lsection_frame"+{-# SPECIALIZE dwarfInfoLabel :: SDoc #-}+{-# SPECIALIZE dwarfInfoLabel :: HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable+{-# SPECIALIZE dwarfAbbrevLabel :: SDoc #-}+{-# SPECIALIZE dwarfAbbrevLabel :: HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable+{-# SPECIALIZE dwarfLineLabel :: SDoc #-}+{-# SPECIALIZE dwarfLineLabel :: HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable+{-# SPECIALIZE dwarfFrameLabel :: SDoc #-}+{-# SPECIALIZE dwarfFrameLabel :: HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Mapping of registers to DWARF register numbers dwarfRegNo :: Platform -> Reg -> Word8
compiler/GHC/CmmToAsm/Dwarf/Types.hs view
@@ -59,9 +59,8 @@                      , dwName :: String                      , dwProducer :: String                      , dwCompDir :: String-                     , dwLowLabel :: SDoc-                     , dwHighLabel :: SDoc-                     , dwLineLabel :: SDoc }+                     , dwLowLabel :: CLabel+                     , dwHighLabel :: CLabel }   | DwarfSubprogram { dwChildren :: [DwarfInfo]                     , dwName :: String                     , dwLabel :: CLabel@@ -88,13 +87,13 @@   deriving (Eq, Enum)  -- | Generate assembly for the given abbreviation code-pprAbbrev :: DwarfAbbrev -> SDoc+pprAbbrev :: IsDoc doc => DwarfAbbrev -> doc pprAbbrev = pprLEBWord . fromIntegral . fromEnum  -- | Abbreviation declaration. This explains the binary encoding we -- use for representing 'DwarfInfo'. Be aware that this must be updated -- along with 'pprDwarfInfo'.-pprAbbrevDecls :: Platform -> Bool -> SDoc+pprAbbrevDecls :: IsDoc doc => Platform -> Bool -> doc pprAbbrevDecls platform haveDebugLine =   let mkAbbrev abbr tag chld flds =         let fld (tag, form) = pprLEBWord tag $$ pprLEBWord form@@ -111,7 +110,7 @@            , (dW_AT_frame_base, dW_FORM_block1)            ]   in dwarfAbbrevSection platform $$-     dwarfAbbrevLabel <> colon $$+     line (dwarfAbbrevLabel <> colon) $$      mkAbbrev DwAbbrCompileUnit dW_TAG_compile_unit dW_CHILDREN_yes        ([(dW_AT_name,     dW_FORM_string)        , (dW_AT_producer, dW_FORM_string)@@ -144,9 +143,11 @@        , (dW_AT_ghc_span_end_col, dW_FORM_data2)        ] $$      pprByte 0+{-# SPECIALIZE pprAbbrevDecls :: Platform -> Bool -> SDoc #-}+{-# SPECIALIZE pprAbbrevDecls :: Platform -> Bool -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Generate assembly for DWARF data-pprDwarfInfo :: Platform -> Bool -> DwarfInfo -> SDoc+pprDwarfInfo :: IsDoc doc => Platform -> Bool -> DwarfInfo -> doc pprDwarfInfo platform haveSrc d   = case d of       DwarfCompileUnit {}  -> hasChildren@@ -159,9 +160,11 @@         vcat (map (pprDwarfInfo platform haveSrc) (dwChildren d)) $$         pprDwarfInfoClose     noChildren = pprDwarfInfoOpen platform haveSrc d+{-# SPECIALIZE pprDwarfInfo :: Platform -> Bool -> DwarfInfo -> SDoc #-}+{-# SPECIALIZE pprDwarfInfo :: Platform -> Bool -> DwarfInfo -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Print a CLabel name in a ".stringz \"LABEL\""-pprLabelString :: Platform -> CLabel -> SDoc+pprLabelString :: IsDoc doc => Platform -> CLabel -> doc pprLabelString platform label =    pprString'                  -- we don't need to escape the string as labels don't contain exotic characters     $ pprCLabel platform label -- pretty-print as C label (foreign labels may be printed differently in Asm)@@ -169,22 +172,22 @@ -- | Prints assembler data corresponding to DWARF info records. Note -- that the binary format of this is parameterized in @abbrevDecls@ and -- has to be kept in synch.-pprDwarfInfoOpen :: Platform -> Bool -> DwarfInfo -> SDoc+pprDwarfInfoOpen :: IsDoc doc => Platform -> Bool -> DwarfInfo -> doc pprDwarfInfoOpen platform haveSrc (DwarfCompileUnit _ name producer compDir lowLabel-                                           highLabel lineLbl) =+                                           highLabel) =   pprAbbrev DwAbbrCompileUnit   $$ pprString name   $$ pprString producer   $$ pprData4 dW_LANG_Haskell   $$ pprString compDir      -- Offset due to Note [Info Offset]-  $$ pprWord platform (lowLabel <> text "-1")-  $$ pprWord platform highLabel+  $$ pprWord platform (pprAsmLabel platform lowLabel <> text "-1")+  $$ pprWord platform (pprAsmLabel platform highLabel)   $$ if haveSrc-     then sectionOffset platform lineLbl dwarfLineLabel+     then sectionOffset platform dwarfLineLabel dwarfLineLabel      else empty pprDwarfInfoOpen platform _ (DwarfSubprogram _ name label parent) =-  pprAsmLabel platform (mkAsmTempDieLabel label) <> colon+  line (pprAsmLabel platform (mkAsmTempDieLabel label) <> colon)   $$ pprAbbrev abbrev   $$ pprString name   $$ pprLabelString platform label@@ -201,11 +204,11 @@     parentValue = maybe empty pprParentDie parent     pprParentDie sym = sectionOffset platform (pprAsmLabel platform sym) dwarfInfoLabel pprDwarfInfoOpen platform _ (DwarfBlock _ label Nothing) =-  pprAsmLabel platform (mkAsmTempDieLabel label) <> colon+  line (pprAsmLabel platform (mkAsmTempDieLabel label) <> colon)   $$ pprAbbrev DwAbbrBlockWithoutCode   $$ pprLabelString platform label pprDwarfInfoOpen platform _ (DwarfBlock _ label (Just marker)) =-  pprAsmLabel platform (mkAsmTempDieLabel label) <> colon+  line (pprAsmLabel platform (mkAsmTempDieLabel label) <> colon)   $$ pprAbbrev DwAbbrBlock   $$ pprLabelString platform label   $$ pprWord platform (pprAsmLabel platform marker)@@ -219,7 +222,7 @@   $$ pprHalf (fromIntegral $ srcSpanEndCol ss)  -- | Close a DWARF info record with children-pprDwarfInfoClose :: SDoc+pprDwarfInfoClose :: IsDoc doc => doc pprDwarfInfoClose = pprAbbrev DwAbbrNull  -- | A DWARF address range. This is used by the debugger to quickly locate@@ -233,7 +236,7 @@  -- | Print assembler directives corresponding to a DWARF @.debug_aranges@ -- address table entry.-pprDwarfARanges :: Platform -> [DwarfARange] -> Unique -> SDoc+pprDwarfARanges :: IsDoc doc => Platform -> [DwarfARange] -> Unique -> doc pprDwarfARanges platform arngs unitU =   let wordSize = platformWordSizeInBytes platform       paddingSize = 4 :: Int@@ -243,7 +246,7 @@       pad n = vcat $ replicate n $ pprByte 0       -- Fix for #17428       initialLength = 8 + paddingSize + (1 + length arngs) * 2 * wordSize-  in pprDwWord (ppr initialLength)+  in pprDwWord (int initialLength)      $$ pprHalf 2      $$ sectionOffset platform (pprAsmLabel platform $ mkAsmTempLabel $ unitU) dwarfInfoLabel      $$ pprByte (fromIntegral wordSize)@@ -254,8 +257,10 @@      -- terminus      $$ pprWord platform (char '0')      $$ pprWord platform (char '0')+{-# SPECIALIZE pprDwarfARanges :: Platform -> [DwarfARange] -> Unique -> SDoc #-}+{-# SPECIALIZE pprDwarfARanges :: Platform -> [DwarfARange] -> Unique -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable -pprDwarfARange :: Platform -> DwarfARange -> SDoc+pprDwarfARange :: IsDoc doc => Platform -> DwarfARange -> doc pprDwarfARange platform arng =     -- Offset due to Note [Info Offset].     pprWord platform (pprAsmLabel platform (dwArngStartLabel arng) <> text "-1")@@ -299,7 +304,7 @@ -- | Header for the @.debug_frame@ section. Here we emit the "Common -- Information Entry" record that establishes general call frame -- parameters and the default stack layout.-pprDwarfFrame :: Platform -> DwarfFrame -> SDoc+pprDwarfFrame :: forall doc. IsDoc doc => Platform -> DwarfFrame -> doc pprDwarfFrame platform DwarfFrame{dwCieLabel=cieLabel,dwCieInit=cieInit,dwCieProcs=procs}   = let cieStartLabel= mkAsmTempDerivedLabel cieLabel (fsLit "_start")         cieEndLabel = mkAsmTempEndLabel cieLabel@@ -307,7 +312,7 @@         spReg       = dwarfGlobalRegNo platform Sp         retReg      = dwarfReturnRegNo platform         wordSize    = platformWordSizeInBytes platform-        pprInit :: (GlobalReg, Maybe UnwindExpr) -> SDoc+        pprInit :: (GlobalReg, Maybe UnwindExpr) -> doc         pprInit (g, uw) = pprSetUnwind platform g (Nothing, uw)          -- Preserve C stack pointer: This necessary to override that default@@ -316,9 +321,9 @@           ArchX86    -> pprByte dW_CFA_same_value $$ pprLEBWord 4           ArchX86_64 -> pprByte dW_CFA_same_value $$ pprLEBWord 7           _          -> empty-    in vcat [ pprAsmLabel platform cieLabel <> colon+    in vcat [ line (pprAsmLabel platform cieLabel <> colon)             , pprData4' length -- Length of CIE-            , pprAsmLabel platform cieStartLabel <> colon+            , line (pprAsmLabel platform cieStartLabel <> colon)             , pprData4' (text "-1")                                -- Common Information Entry marker (-1 = 0xf..f)             , pprByte 3        -- CIE version (we require DWARF 3)@@ -346,23 +351,25 @@             , pprLEBWord 0             ] $$        wordAlign platform $$-       pprAsmLabel platform cieEndLabel <> colon $$+       line (pprAsmLabel platform cieEndLabel <> colon) $$        -- Procedure unwind tables        vcat (map (pprFrameProc platform cieLabel cieInit) procs)+{-# SPECIALIZE pprDwarfFrame :: Platform -> DwarfFrame -> SDoc #-}+{-# SPECIALIZE pprDwarfFrame :: Platform -> DwarfFrame -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Writes a "Frame Description Entry" for a procedure. This consists -- mainly of referencing the CIE and writing state machine -- instructions to describe how the frame base (CFA) changes.-pprFrameProc :: Platform -> CLabel -> UnwindTable -> DwarfFrameProc -> SDoc+pprFrameProc :: IsDoc doc => Platform -> CLabel -> UnwindTable -> DwarfFrameProc -> doc pprFrameProc platform frameLbl initUw (DwarfFrameProc procLbl hasInfo blocks)   = let fdeLabel    = mkAsmTempDerivedLabel procLbl (fsLit "_fde")         fdeEndLabel = mkAsmTempDerivedLabel procLbl (fsLit "_fde_end")         procEnd     = mkAsmTempProcEndLabel procLbl         ifInfo str  = if hasInfo then text str else empty                       -- see Note [Info Offset]-    in vcat [ whenPprDebug $ text "# Unwinding for" <+> pprAsmLabel platform procLbl <> colon+    in vcat [ whenPprDebug $ line $ text "# Unwinding for" <+> pprAsmLabel platform procLbl <> colon             , pprData4' (pprAsmLabel platform fdeEndLabel <> char '-' <> pprAsmLabel platform fdeLabel)-            , pprAsmLabel platform fdeLabel <> colon+            , line (pprAsmLabel platform fdeLabel <> colon)             , pprData4' (pprAsmLabel platform frameLbl <> char '-' <> dwarfFrameLabel)    -- Reference to CIE             , pprWord platform (pprAsmLabel platform procLbl <> ifInfo "-1") -- Code pointer             , pprWord platform (pprAsmLabel platform procEnd <> char '-' <>@@ -370,17 +377,17 @@             ] $$        vcat (S.evalState (mapM (pprFrameBlock platform) blocks) initUw) $$        wordAlign platform $$-       pprAsmLabel platform fdeEndLabel <> colon+       line (pprAsmLabel platform fdeEndLabel <> colon)  -- | Generates unwind information for a block. We only generate -- instructions where unwind information actually changes. This small -- optimisations saves a lot of space, as subsequent blocks often have -- the same unwind information.-pprFrameBlock :: Platform -> DwarfFrameBlock -> S.State UnwindTable SDoc+pprFrameBlock :: forall doc. IsDoc doc => Platform -> DwarfFrameBlock -> S.State UnwindTable doc pprFrameBlock platform (DwarfFrameBlock hasInfo uws0) =     vcat <$> zipWithM pprFrameDecl (True : repeat False) uws0   where-    pprFrameDecl :: Bool -> UnwindPoint -> S.State UnwindTable SDoc+    pprFrameDecl :: Bool -> UnwindPoint -> S.State UnwindTable doc     pprFrameDecl firstDecl (UnwindPoint lbl uws) = S.state $ \oldUws ->         let -- Did a register's unwind expression change?             isChanged :: GlobalReg -> Maybe UnwindExpr@@ -450,12 +457,12 @@ -- | Generate code for setting the unwind information for a register, -- optimized using its known old value in the table. Note that "Sp" is -- special: We see it as synonym for the CFA.-pprSetUnwind :: Platform+pprSetUnwind :: IsDoc doc => Platform              -> GlobalReg                 -- ^ the register to produce an unwinding table entry for              -> (Maybe UnwindExpr, Maybe UnwindExpr)                 -- ^ the old and new values of the register-             -> SDoc+             -> doc pprSetUnwind plat g  (_, Nothing)   = pprUndefUnwind plat g pprSetUnwind _    Sp (Just (UwReg s _), Just (UwReg s' o')) | s == s'@@ -495,13 +502,13 @@  -- | Print the register number of the given 'GlobalReg' as an unsigned LEB128 -- encoded number.-pprLEBRegNo :: Platform -> GlobalReg -> SDoc+pprLEBRegNo :: IsDoc doc => Platform -> GlobalReg -> doc pprLEBRegNo plat = pprLEBWord . fromIntegral . dwarfGlobalRegNo plat  -- | Generates a DWARF expression for the given unwind expression. If -- @spIsCFA@ is true, we see @Sp@ as the frame base CFA where it gets -- mentioned.-pprUnwindExpr :: Platform -> Bool -> UnwindExpr -> SDoc+pprUnwindExpr :: IsDoc doc => Platform -> Bool -> UnwindExpr -> doc pprUnwindExpr platform spIsCFA expr   = let pprE (UwConst i)           | i >= 0 && i < 32 = pprByte (dW_OP_lit0 + fromIntegral i)@@ -517,84 +524,100 @@         pprE (UwPlus u1 u2)   = pprE u1 $$ pprE u2 $$ pprByte dW_OP_plus         pprE (UwMinus u1 u2)  = pprE u1 $$ pprE u2 $$ pprByte dW_OP_minus         pprE (UwTimes u1 u2)  = pprE u1 $$ pprE u2 $$ pprByte dW_OP_mul-    in text "\t.uleb128 2f-1f" $$ -- DW_FORM_block length+    in line (text "\t.uleb128 2f-1f") $$ -- DW_FORM_block length        -- computed as the difference of the following local labels 2: and 1:-       text "1:" $$+       line (text "1:") $$        pprE expr $$-       text "2:"+       line (text "2:")  -- | Generate code for re-setting the unwind information for a -- register to @undefined@-pprUndefUnwind :: Platform -> GlobalReg -> SDoc+pprUndefUnwind :: IsDoc doc => Platform -> GlobalReg -> doc pprUndefUnwind plat g  = pprByte dW_CFA_undefined $$                          pprLEBRegNo plat g   -- | Align assembly at (machine) word boundary-wordAlign :: Platform -> SDoc+wordAlign :: IsDoc doc => Platform -> doc wordAlign plat =-  text "\t.align " <> case platformOS plat of+  line $ text "\t.align " <> case platformOS plat of     OSDarwin -> case platformWordSize plat of       PW8 -> char '3'       PW4 -> char '2'-    _other   -> ppr (platformWordSizeInBytes plat)+    _other   -> int (platformWordSizeInBytes plat)+{-# SPECIALIZE wordAlign :: Platform -> SDoc #-}+{-# SPECIALIZE wordAlign :: Platform -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Assembly for a single byte of constant DWARF data-pprByte :: Word8 -> SDoc-pprByte x = text "\t.byte " <> ppr (fromIntegral x :: Word)+pprByte :: IsDoc doc => Word8 -> doc+pprByte x = line $ text "\t.byte " <> integer (fromIntegral x)+{-# SPECIALIZE pprByte :: Word8 -> SDoc #-}+{-# SPECIALIZE pprByte :: Word8 -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Assembly for a two-byte constant integer-pprHalf :: Word16 -> SDoc-pprHalf x = text "\t.short" <+> ppr (fromIntegral x :: Word)+pprHalf :: IsDoc doc => Word16 -> doc+pprHalf x = line $ text "\t.short" <+> integer (fromIntegral x)+{-# SPECIALIZE pprHalf :: Word16 -> SDoc #-}+{-# SPECIALIZE pprHalf :: Word16 -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Assembly for a constant DWARF flag-pprFlag :: Bool -> SDoc+pprFlag :: IsDoc doc => Bool -> doc pprFlag f = pprByte (if f then 0xff else 0x00)  -- | Assembly for 4 bytes of dynamic DWARF data-pprData4' :: SDoc -> SDoc-pprData4' x = text "\t.long " <> x+pprData4' :: IsDoc doc => Line doc -> doc+pprData4' x = line (text "\t.long " <> x)+{-# SPECIALIZE pprData4' :: SDoc -> SDoc #-}+{-# SPECIALIZE pprData4' :: HLine -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Assembly for 4 bytes of constant DWARF data-pprData4 :: Word -> SDoc-pprData4 = pprData4' . ppr+pprData4 :: IsDoc doc => Word -> doc+pprData4 = pprData4' . integer . fromIntegral  -- | Assembly for a DWARF word of dynamic data. This means 32 bit, as -- we are generating 32 bit DWARF.-pprDwWord :: SDoc -> SDoc+pprDwWord :: IsDoc doc => Line doc -> doc pprDwWord = pprData4'+{-# SPECIALIZE pprDwWord :: SDoc -> SDoc #-}+{-# SPECIALIZE pprDwWord :: HLine -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Assembly for a machine word of dynamic data. Depends on the -- architecture we are currently generating code for.-pprWord :: Platform -> SDoc -> SDoc+pprWord :: IsDoc doc => Platform -> Line doc -> doc pprWord plat s =-  case platformWordSize plat of+  line $ case platformWordSize plat of     PW4 -> text "\t.long " <> s     PW8 -> text "\t.quad " <> s+{-# SPECIALIZE pprWord :: Platform -> SDoc -> SDoc #-}+{-# SPECIALIZE pprWord :: Platform -> HLine -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Prints a number in "little endian base 128" format. The idea is -- to optimize for small numbers by stopping once all further bytes -- would be 0. The highest bit in every byte signals whether there -- are further bytes to read.-pprLEBWord :: Word -> SDoc+pprLEBWord :: IsDoc doc => Word -> doc pprLEBWord x | x < 128   = pprByte (fromIntegral x)              | otherwise = pprByte (fromIntegral $ 128 .|. (x .&. 127)) $$                            pprLEBWord (x `shiftR` 7)+{-# SPECIALIZE pprLEBWord :: Word -> SDoc #-}+{-# SPECIALIZE pprLEBWord :: Word -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Same as @pprLEBWord@, but for a signed number-pprLEBInt :: Int -> SDoc+pprLEBInt :: IsDoc doc => Int -> doc pprLEBInt x | x >= -64 && x < 64                         = pprByte (fromIntegral (x .&. 127))             | otherwise = pprByte (fromIntegral $ 128 .|. (x .&. 127)) $$                           pprLEBInt (x `shiftR` 7)+{-# SPECIALIZE pprLEBInt :: Int -> SDoc #-}+{-# SPECIALIZE pprLEBInt :: Int -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Generates a dynamic null-terminated string. If required the -- caller needs to make sure that the string is escaped properly.-pprString' :: SDoc -> SDoc-pprString' str = text "\t.asciz \"" <> str <> char '"'+pprString' :: IsDoc doc => Line doc -> doc+pprString' str = line (text "\t.asciz \"" <> str <> char '"')  -- | Generate a string constant. We take care to escape the string.-pprString :: String -> SDoc+pprString :: IsDoc doc => String -> doc pprString str   = pprString' $ hcat $ map escapeChar $     if str `lengthIs` utf8EncodedLength str@@ -602,7 +625,7 @@     else map (chr . fromIntegral) $ BS.unpack $ utf8EncodeByteString str  -- | Escape a single non-unicode character-escapeChar :: Char -> SDoc+escapeChar :: IsLine doc => Char -> doc escapeChar '\\' = text "\\\\" escapeChar '\"' = text "\\\"" escapeChar '\n' = text "\\n"@@ -621,9 +644,11 @@ -- us to just reference the target directly, and will figure out on -- their own that we actually need an offset. Finally, Windows has -- a special directive to refer to relative offsets. Fun.-sectionOffset :: Platform -> SDoc -> SDoc -> SDoc+sectionOffset :: IsDoc doc => Platform -> Line doc -> Line doc -> doc sectionOffset plat target section =   case platformOS plat of     OSDarwin  -> pprDwWord (target <> char '-' <> section)-    OSMinGW32 -> text "\t.secrel32 " <> target+    OSMinGW32 -> line (text "\t.secrel32 " <> target)     _other    -> pprDwWord target+{-# SPECIALIZE sectionOffset :: Platform -> SDoc -> SDoc -> SDoc #-}+{-# SPECIALIZE sectionOffset :: Platform -> HLine -> HLine -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
compiler/GHC/CmmToAsm/Instr.hs view
@@ -15,6 +15,7 @@ import GHC.Cmm.BlockId  import GHC.CmmToAsm.Config+import GHC.Data.FastString  -- | Holds a list of source and destination registers used by a --      particular instruction.@@ -160,4 +161,4 @@         pprInstr :: Platform -> instr -> SDoc          -- Create a comment instruction-        mkComment :: SDoc -> [instr]+        mkComment :: FastString -> [instr]
compiler/GHC/CmmToAsm/Monad.hs view
@@ -67,7 +67,7 @@ import GHC.Types.Unique         ( Unique ) import GHC.Unit.Module -import GHC.Utils.Outputable (SDoc, ppr)+import GHC.Utils.Outputable (SDoc, HDoc, ppr) import GHC.Utils.Panic      (pprPanic) import GHC.Utils.Monad.State.Strict (State (..), runState, state) import GHC.Utils.Misc@@ -84,7 +84,9 @@     shortcutJump              :: (BlockId -> Maybe jumpDest) -> instr -> instr,     -- | 'Module' is only for printing internal labels. See Note [Internal proc     -- labels] in CLabel.-    pprNatCmmDecl             :: NatCmmDecl statics instr -> SDoc,+    pprNatCmmDeclS            :: NatCmmDecl statics instr -> SDoc,+    pprNatCmmDeclH            :: NatCmmDecl statics instr -> HDoc,+        -- see Note [pprNatCmmDeclS and pprNatCmmDeclH]     maxSpillSlots             :: Int,     allocatableRegs           :: [RealReg],     ncgAllocMoreStack         :: Int -> NatCmmDecl statics instr@@ -102,6 +104,38 @@     -- ^ Turn the sequence of @jcc l1; jmp l2@ into @jncc l2; \<block_l1>@     -- when possible.     }++{- Note [pprNatCmmDeclS and pprNatCmmDeclH]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Each NcgImpl provides two implementations of its CmmDecl printer, pprNatCmmDeclS+and pprNatCmmDeclH, which are specialized to SDoc and HDoc, respectively+(see Note [SDoc versus HDoc] in GHC.Utils.Outputable). These are both internally+implemented as a single, polymorphic function, but they need to be stored using+monomorphic types to ensure the specialized versions are used, which is+essential for performance (see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable).++One might wonder why we bother with pprNatCmmDeclS and SDoc at all, since we+have a perfectly serviceable HDoc-based implementation that is more efficient.+However, it turns out we benefit from keeping both, for two (related) reasons:++  1. Although we absolutely want to take care to use pprNatCmmDeclH for actual+     code generation (the improved performance there is why we have HDoc at+     all!), we also sometimes print assembly for debug dumps, when requested via+     -ddump-asm. In this case, it’s more convenient to produce an SDoc, which+     can be concatenated with other SDocs for consistency with the general-+     purpose dump file infrastructure.++  2. Some debug information is sometimes useful to include in -ddump-asm that is+     neither necessary nor useful in normal code generation, and it turns out to+     be tricky to format neatly using the one-line-at-a-time model of HLine/HDoc.++Therefore, we provide both pprNatCmmDeclS and pprNatCmmDeclH, and we sometimes+include additional information in the SDoc variant using dualDoc+(see Note [dualLine and dualDoc] in GHC.Utils.Outputable). However, it is+absolutely *critical* that pprNatCmmDeclS is not actually used unless -ddump-asm+is provided, as that would rather defeat the whole point. (Fortunately, the+difference in allocations between the two implementations is so vast that such a+mistake would readily show up in performance tests). -}  data NatM_State         = NatM_State {
compiler/GHC/CmmToAsm/PIC.hs view
@@ -532,11 +532,11 @@ -- -- We don't need to declare any offset tables. -- However, for PIC on x86, we need a small helper function.-pprGotDeclaration :: NCGConfig -> SDoc+pprGotDeclaration :: NCGConfig -> HDoc pprGotDeclaration config = case (arch,os) of    (ArchX86, OSDarwin)         | ncgPIC config-        -> vcat [+        -> lines_ [                 text ".section __TEXT,__textcoal_nt,coalesced,no_toc",                 text ".weak_definition ___i686.get_pc_thunk.ax",                 text ".private_extern ___i686.get_pc_thunk.ax",@@ -548,7 +548,7 @@     -- Emit XCOFF TOC section    (_, OSAIX)-        -> vcat $ [ text ".toc"+        -> lines_ [ text ".toc"                   , text ".tc ghc_toc_table[TC],.LCTOC1"                   , text ".csect ghc_toc_table[RW]"                     -- See Note [.LCTOC1 in PPC PIC code]@@ -558,16 +558,16 @@     -- PPC 64 ELF v1 needs a Table Of Contents (TOC)    (ArchPPC_64 ELF_V1, _)-        -> text ".section \".toc\",\"aw\""+        -> line $ text ".section \".toc\",\"aw\""     -- In ELF v2 we also need to tell the assembler that we want ABI    -- version 2. This would normally be done at the top of the file    -- right after a file directive, but I could not figure out how    -- to do that.    (ArchPPC_64 ELF_V2, _)-        -> vcat [ text ".abiversion 2",-                  text ".section \".toc\",\"aw\""-                ]+        -> lines_ [ text ".abiversion 2",+                    text ".section \".toc\",\"aw\""+                  ]     (arch, os)         | osElfTarget os@@ -577,7 +577,7 @@          | osElfTarget os         , arch /= ArchPPC_64 ELF_V1 && arch /= ArchPPC_64 ELF_V2-        -> vcat [+        -> lines_ [                 -- See Note [.LCTOC1 in PPC PIC code]                 text ".section \".got2\",\"aw\"",                 text ".LCTOC1 = .+32768" ]@@ -595,13 +595,13 @@ -- and one for non-PIC. -- -pprImportedSymbol :: NCGConfig -> CLabel -> SDoc+pprImportedSymbol :: NCGConfig -> CLabel -> HDoc pprImportedSymbol config importedLbl = case (arch,os) of    (ArchX86, OSDarwin)         | Just (CodeStub, lbl) <- dynamicLinkerLabelInfo importedLbl         -> if not pic              then-              vcat [+              lines_ [                   text ".symbol_stub",                   text "L" <> ppr_lbl lbl <> text "$stub:",                       text "\t.indirect_symbol" <+> ppr_lbl lbl,@@ -614,7 +614,7 @@                       text "\tjmp dyld_stub_binding_helper"               ]              else-              vcat [+              lines_ [                   text ".section __TEXT,__picsymbolstub2,"                       <> text "symbol_stubs,pure_instructions,25",                   text "L" <> ppr_lbl lbl <> text "$stub:",@@ -631,7 +631,8 @@                       text "\tpushl %eax",                       text "\tjmp dyld_stub_binding_helper"               ]-           $+$ vcat [        text ".section __DATA, __la_sym_ptr"+           $$ lines_ [+                text ".section __DATA, __la_sym_ptr"                     <> (if pic then int 2 else int 3)                     <> text ",lazy_symbol_pointers",                 text "L" <> ppr_lbl lbl <> text "$lazy_ptr:",@@ -640,7 +641,7 @@                     <> text "$stub_binder"]          | Just (SymbolPtr, lbl) <- dynamicLinkerLabelInfo importedLbl-        -> vcat [+        -> lines_ [                 text ".non_lazy_symbol_pointer",                 char 'L' <> ppr_lbl lbl <> text "$non_lazy_ptr:",                 text "\t.indirect_symbol" <+> ppr_lbl lbl,@@ -667,7 +668,7 @@     (_, OSAIX) -> case dynamicLinkerLabelInfo importedLbl of             Just (SymbolPtr, lbl)-              -> vcat [+              -> lines_ [                    text "LC.." <> ppr_lbl lbl <> char ':',                    text "\t.long" <+> ppr_lbl lbl ]             _ -> empty@@ -705,7 +706,7 @@         | osElfTarget os         -> case dynamicLinkerLabelInfo importedLbl of             Just (SymbolPtr, lbl)-              -> vcat [+              -> lines_ [                    text ".LC_" <> ppr_lbl lbl <> char ':',                    text "\t.quad" <+> ppr_lbl lbl ]             _ -> empty@@ -718,7 +719,7 @@                          W64 -> text "\t.quad"                          _ -> panic "Unknown wordRep in pprImportedSymbol" -                 in vcat [+                 in lines_ [                       text ".section \".got2\", \"aw\"",                       text ".LC_" <> ppr_lbl lbl <> char ':',                       symbolSize <+> ppr_lbl lbl ]@@ -729,6 +730,7 @@    _ -> panic "PIC.pprImportedSymbol: no match"  where    platform = ncgPlatform config+   ppr_lbl :: CLabel -> HLine    ppr_lbl  = pprAsmLabel   platform    arch     = platformArch  platform    os       = platformOS    platform
compiler/GHC/CmmToAsm/PPC.hs view
@@ -28,7 +28,8 @@    , canShortcut               = PPC.canShortcut    , shortcutStatics           = PPC.shortcutStatics    , shortcutJump              = PPC.shortcutJump-   , pprNatCmmDecl             = PPC.pprNatCmmDecl config+   , pprNatCmmDeclH            = PPC.pprNatCmmDecl config+   , pprNatCmmDeclS            = PPC.pprNatCmmDecl config    , maxSpillSlots             = PPC.maxSpillSlots config    , allocatableRegs           = PPC.allocatableRegs platform    , ncgAllocMoreStack         = PPC.allocMoreStack platform
compiler/GHC/CmmToAsm/PPC/CodeGen.hs view
@@ -162,7 +162,7 @@   config <- getConfig   platform <- getPlatform   case stmt of-    CmmComment s   -> return (unitOL (COMMENT $ ftext s))+    CmmComment s   -> return (unitOL (COMMENT s))     CmmTick {}     -> return nilOL     CmmUnwind {}   -> return nilOL @@ -407,7 +407,7 @@ getRegister' _ platform (CmmReg (CmmGlobal PicBaseReg))   | OSAIX <- platformOS platform = do         let code dst = toOL [ LD II32 dst tocAddr ]-            tocAddr = AddrRegImm toc (ImmLit "ghc_toc_table[TC]")+            tocAddr = AddrRegImm toc (ImmLit (fsLit "ghc_toc_table[TC]"))         return (Any II32 code)   | target32Bit platform = do       reg <- getPicBaseNat $ archWordFormat (target32Bit platform)
compiler/GHC/CmmToAsm/PPC/Instr.hs view
@@ -52,7 +52,6 @@ import GHC.Cmm import GHC.Cmm.Info import GHC.Cmm.CLabel-import GHC.Utils.Outputable import GHC.Utils.Panic import GHC.Platform import GHC.Types.Unique.FM (listToUFM, lookupUFM)@@ -60,6 +59,7 @@  import Data.Foldable (toList) import qualified Data.List.NonEmpty as NE+import GHC.Data.FastString (FastString) import Data.Maybe (fromMaybe)  @@ -179,7 +179,7 @@  data Instr     -- comment pseudo-op-    = COMMENT SDoc+    = COMMENT FastString      -- location pseudo-op (file, line, col, name)     | LOCATION Int Int Int String
compiler/GHC/CmmToAsm/PPC/Ppr.hs view
@@ -46,7 +46,7 @@ -- ----------------------------------------------------------------------------- -- Printing this stuff out -pprNatCmmDecl :: NCGConfig -> NatCmmDecl RawCmmStatics Instr -> SDoc+pprNatCmmDecl :: IsDoc doc => NCGConfig -> NatCmmDecl RawCmmStatics Instr -> doc pprNatCmmDecl config (CmmData section dats) =   pprSectionAlign config section   $$ pprDatas (ncgPlatform config) dats@@ -63,15 +63,15 @@             _ -> pprLabel platform lbl) $$ -- blocks guaranteed not null,                                            -- so label needed          vcat (map (pprBasicBlock config top_info) blocks) $$-         ppWhen (ncgDwarfEnabled config) (pprAsmLabel platform (mkAsmTempEndLabel lbl)-                                          <> char ':' $$-                                          pprProcEndLabel platform lbl) $$+         ppWhen (ncgDwarfEnabled config) (line (pprAsmLabel platform (mkAsmTempEndLabel lbl)+                                                <> char ':') $$+                                          line (pprProcEndLabel platform lbl)) $$          pprSizeDecl platform lbl      Just (CmmStaticsRaw info_lbl _) ->       pprSectionAlign config (Section Text info_lbl) $$       (if platformHasSubsectionsViaSymbols platform-          then pprAsmLabel platform (mkDeadStripPreventer info_lbl) <> char ':'+          then line (pprAsmLabel platform (mkDeadStripPreventer info_lbl) <> char ':')           else empty) $$       vcat (map (pprBasicBlock config top_info) blocks) $$       -- above: Even the first block gets a label, because with branch-chain@@ -79,18 +79,20 @@       (if platformHasSubsectionsViaSymbols platform        then        -- See Note [Subsections Via Symbols] in X86/Ppr.hs-                text "\t.long "-            <+> pprAsmLabel platform info_lbl-            <+> char '-'-            <+> pprAsmLabel platform (mkDeadStripPreventer info_lbl)+                line (text "\t.long "+                      <+> pprAsmLabel platform info_lbl+                      <+> char '-'+                      <+> pprAsmLabel platform (mkDeadStripPreventer info_lbl))        else empty) $$       pprSizeDecl platform info_lbl+{-# SPECIALIZE pprNatCmmDecl :: NCGConfig -> NatCmmDecl RawCmmStatics Instr -> SDoc #-}+{-# SPECIALIZE pprNatCmmDecl :: NCGConfig -> NatCmmDecl RawCmmStatics Instr -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Output the ELF .size directive.-pprSizeDecl :: Platform -> CLabel -> SDoc+pprSizeDecl :: IsDoc doc => Platform -> CLabel -> doc pprSizeDecl platform lbl  = if osElfTarget (platformOS platform)-   then text "\t.size" <+> prettyLbl <> text ", .-" <> codeLbl+   then line (text "\t.size" <+> prettyLbl <> text ", .-" <> codeLbl)    else empty   where     prettyLbl = pprAsmLabel platform lbl@@ -98,47 +100,45 @@       | platformArch platform == ArchPPC_64 ELF_V1 = char '.' <> prettyLbl       | otherwise                                  = prettyLbl -pprFunctionDescriptor :: Platform -> CLabel -> SDoc-pprFunctionDescriptor platform lab = pprGloblDecl platform lab-                        $$  text "\t.section \".opd\", \"aw\""-                        $$  text "\t.align 3"-                        $$  pprAsmLabel platform lab <> char ':'-                        $$  text "\t.quad ."-                        <>  pprAsmLabel platform lab-                        <>  text ",.TOC.@tocbase,0"-                        $$  text "\t.previous"-                        $$  text "\t.type"-                        <+> pprAsmLabel platform lab-                        <>  text ", @function"-                        $$  char '.' <> pprAsmLabel platform lab <> char ':'+pprFunctionDescriptor :: IsDoc doc => Platform -> CLabel -> doc+pprFunctionDescriptor platform lab =+  vcat [pprGloblDecl platform lab,+        line (text "\t.section \".opd\", \"aw\""),+        line (text "\t.align 3"),+        line (pprAsmLabel platform lab <> char ':'),+        line (text "\t.quad ."+              <>  pprAsmLabel platform lab+              <>  text ",.TOC.@tocbase,0"),+        line (text "\t.previous"),+        line (text "\t.type"+              <+> pprAsmLabel platform lab+              <>  text ", @function"),+        line (char '.' <> pprAsmLabel platform lab <> char ':')] -pprFunctionPrologue :: Platform -> CLabel ->SDoc-pprFunctionPrologue platform lab =  pprGloblDecl platform lab-                        $$  text ".type "-                        <> pprAsmLabel platform lab-                        <> text ", @function"-                        $$ pprAsmLabel platform lab <> char ':'-                        $$ text "0:\taddis\t" <> pprReg toc-                        <> text ",12,.TOC.-0b@ha"-                        $$ text "\taddi\t" <> pprReg toc-                        <> char ',' <> pprReg toc <> text ",.TOC.-0b@l"-                        $$ text "\t.localentry\t" <> pprAsmLabel platform lab-                        <> text ",.-" <> pprAsmLabel platform lab+pprFunctionPrologue :: IsDoc doc => Platform -> CLabel -> doc+pprFunctionPrologue platform lab =+  vcat [pprGloblDecl platform lab,+        line (text ".type " <> pprAsmLabel platform lab <> text ", @function"),+        line (pprAsmLabel platform lab <> char ':'),+        line (text "0:\taddis\t" <> pprReg toc <> text ",12,.TOC.-0b@ha"),+        line (text "\taddi\t" <> pprReg toc <> char ',' <> pprReg toc <> text ",.TOC.-0b@l"),+        line (text "\t.localentry\t" <> pprAsmLabel platform lab <>+              text ",.-" <> pprAsmLabel platform lab)] -pprProcEndLabel :: Platform -> CLabel -- ^ Procedure name-                -> SDoc+pprProcEndLabel :: IsLine doc => Platform -> CLabel -- ^ Procedure name+                -> doc pprProcEndLabel platform lbl =     pprAsmLabel platform (mkAsmTempProcEndLabel lbl) <> char ':' -pprBasicBlock :: NCGConfig -> LabelMap RawCmmStatics -> NatBasicBlock Instr-              -> SDoc+pprBasicBlock :: IsDoc doc => NCGConfig -> LabelMap RawCmmStatics -> NatBasicBlock Instr+              -> doc pprBasicBlock config info_env (BasicBlock blockid instrs)   = maybe_infotable $$     pprLabel platform asmLbl $$     vcat (map (pprInstr platform) instrs) $$     ppWhen (ncgDwarfEnabled config) (-      pprAsmLabel platform (mkAsmTempEndLabel asmLbl) <> char ':'-      <> pprProcEndLabel platform asmLbl+      line (pprAsmLabel platform (mkAsmTempEndLabel asmLbl) <> char ':'+            <> pprProcEndLabel platform asmLbl)     )   where     asmLbl = blockLbl blockid@@ -152,7 +152,7 @@   -pprDatas :: Platform -> RawCmmStatics -> SDoc+pprDatas :: IsDoc doc => Platform -> RawCmmStatics -> doc -- See Note [emit-time elimination of static indirections] in "GHC.Cmm.CLabel". pprDatas platform (CmmStaticsRaw alias [CmmStaticLit (CmmLabel lbl), CmmStaticLit ind, _, _])   | lbl == mkIndStaticInfoLabel@@ -162,38 +162,38 @@   , Just ind' <- labelInd ind   , alias `mayRedirectTo` ind'   = pprGloblDecl platform alias-    $$ text ".equiv" <+> pprAsmLabel platform alias <> comma <> pprAsmLabel platform ind'+    $$ line (text ".equiv" <+> pprAsmLabel platform alias <> comma <> pprAsmLabel platform ind') pprDatas platform (CmmStaticsRaw lbl dats) = vcat (pprLabel platform lbl : map (pprData platform) dats) -pprData :: Platform -> CmmStatic -> SDoc+pprData :: IsDoc doc => Platform -> CmmStatic -> doc pprData platform d = case d of-   CmmString str          -> pprString str-   CmmFileEmbed path      -> pprFileEmbed path-   CmmUninitialised bytes -> text ".space " <> int bytes+   CmmString str          -> line (pprString str)+   CmmFileEmbed path _    -> line (pprFileEmbed path)+   CmmUninitialised bytes -> line (text ".space " <> int bytes)    CmmStaticLit lit       -> pprDataItem platform lit -pprGloblDecl :: Platform -> CLabel -> SDoc+pprGloblDecl :: IsDoc doc => Platform -> CLabel -> doc pprGloblDecl platform lbl   | not (externallyVisibleCLabel lbl) = empty-  | otherwise = text ".globl " <> pprAsmLabel platform lbl+  | otherwise = line (text ".globl " <> pprAsmLabel platform lbl) -pprTypeAndSizeDecl :: Platform -> CLabel -> SDoc+pprTypeAndSizeDecl :: IsLine doc => Platform -> CLabel -> doc pprTypeAndSizeDecl platform lbl   = if platformOS platform == OSLinux && externallyVisibleCLabel lbl     then text ".type " <>          pprAsmLabel platform lbl <> text ", @object"     else empty -pprLabel :: Platform -> CLabel -> SDoc+pprLabel :: IsDoc doc => Platform -> CLabel -> doc pprLabel platform lbl =    pprGloblDecl platform lbl-   $$ pprTypeAndSizeDecl platform lbl-   $$ (pprAsmLabel platform lbl <> char ':')+   $$ line (pprTypeAndSizeDecl platform lbl)+   $$ line (pprAsmLabel platform lbl <> char ':')  -- ----------------------------------------------------------------------------- -- pprInstr: print an 'Instr' -pprReg :: Reg -> SDoc+pprReg :: forall doc. IsLine doc => Reg -> doc  pprReg r   = case r of@@ -204,7 +204,7 @@       RegVirtual (VirtualRegD  u)  -> text "%vD_"   <> pprUniqueAlways u    where-    ppr_reg_no :: Int -> SDoc+    ppr_reg_no :: Int -> doc     ppr_reg_no i          | i <= 31   = int i      -- GPRs          | i <= 63   = int (i-32) -- FPRs@@ -212,7 +212,7 @@   -pprFormat :: Format -> SDoc+pprFormat :: IsLine doc => Format -> doc pprFormat x  = case x of                 II8  -> text "b"@@ -223,7 +223,7 @@                 FF64 -> text "fd"  -pprCond :: Cond -> SDoc+pprCond :: IsLine doc => Cond -> doc pprCond c  = case c of {                 ALWAYS  -> text "";@@ -234,13 +234,13 @@                 GU      -> text "gt";  LEU   -> text "le"; }  -pprImm :: Platform -> Imm -> SDoc+pprImm :: IsLine doc => Platform -> Imm -> doc pprImm platform = \case    ImmInt i       -> int i    ImmInteger i   -> integer i    ImmCLbl l      -> pprAsmLabel platform l    ImmIndex l i   -> pprAsmLabel platform l <> char '+' <> int i-   ImmLit s       -> text s+   ImmLit s       -> ftext s    ImmFloat f     -> float $ fromRational f    ImmDouble d    -> double $ fromRational d    ImmConstantSum a b   -> pprImm platform a <> char '+' <> pprImm platform b@@ -264,7 +264,7 @@    HIGHESTA i  -> pprImm platform i <> text "@highesta"  -pprAddr :: Platform -> AddrMode -> SDoc+pprAddr :: IsLine doc => Platform -> AddrMode -> doc pprAddr platform = \case    AddrRegReg r1 r2             -> pprReg r1 <> char ',' <+> pprReg r2    AddrRegImm r1 (ImmInt i)     -> hcat [ int i, char '(', pprReg r1, char ')' ]@@ -272,14 +272,14 @@    AddrRegImm r1 imm            -> hcat [ pprImm platform imm, char '(', pprReg r1, char ')' ]  -pprSectionAlign :: NCGConfig -> Section -> SDoc+pprSectionAlign :: IsDoc doc => NCGConfig -> Section -> doc pprSectionAlign config sec@(Section seg _) =-   pprSectionHeader config sec $$+   line (pprSectionHeader config sec) $$    pprAlignForSection (ncgPlatform config) seg  -- | Print appropriate alignment for the given section type.-pprAlignForSection :: Platform -> SectionType -> SDoc-pprAlignForSection platform seg =+pprAlignForSection :: IsDoc doc => Platform -> SectionType -> doc+pprAlignForSection platform seg = line $  let ppc64    = not $ target32Bit platform  in case seg of        Text              -> text ".align 2"@@ -304,9 +304,9 @@         | otherwise      -> text ".align 2"        OtherSection _    -> panic "PprMach.pprSectionAlign: unknown section" -pprDataItem :: Platform -> CmmLit -> SDoc+pprDataItem :: IsDoc doc => Platform -> CmmLit -> doc pprDataItem platform lit-  = vcat (ppr_item (cmmTypeFormat $ cmmLitType platform lit) lit)+  = lines_ (ppr_item (cmmTypeFormat $ cmmLitType platform lit) lit)     where         imm = litToImm lit         archPPC_64 = not $ target32Bit platform@@ -333,21 +333,21 @@                 = panic "PPC.Ppr.pprDataItem: no match"  -asmComment :: SDoc -> SDoc+asmComment :: IsLine doc => doc -> doc asmComment c = whenPprDebug $ text "#" <+> c  -pprInstr :: Platform -> Instr -> SDoc+pprInstr :: IsDoc doc => Platform -> Instr -> doc pprInstr platform instr = case instr of     COMMENT s-      -> asmComment s+      -> line (asmComment (ftext s)) -   LOCATION file line col _name-      -> text "\t.loc" <+> ppr file <+> ppr line <+> ppr col+   LOCATION file line' col _name+      -> line (text "\t.loc" <+> int file <+> int line' <+> int col)     DELTA d-      -> asmComment $ text ("\tdelta = " ++ show d)+      -> line (asmComment $ text ("\tdelta = " ++ show d))     NEWBLOCK _       -> panic "PprMach.pprInstr: NEWBLOCK"@@ -374,7 +374,7 @@ -}     LD fmt reg addr-      -> hcat [+      -> line $ hcat [            char '\t',            text "l",            (case fmt of@@ -403,7 +403,7 @@       -> panic "PPC.Ppr.pprInstr LDFAR: no match"     LDR fmt reg1 addr-      -> hcat [+      -> line $ hcat [            text "\tl",            case fmt of              II32 -> char 'w'@@ -416,7 +416,7 @@            ]     LA fmt reg addr-      -> hcat [+      -> line $ hcat [            char '\t',            text "l",            (case fmt of@@ -436,7 +436,7 @@            ]     ST fmt reg addr-      -> hcat [+      -> line $ hcat [            char '\t',            text "st",            pprFormat fmt,@@ -457,7 +457,7 @@       -> panic "PPC.Ppr.pprInstr STFAR: no match"     STU fmt reg addr-      -> hcat [+      -> line $ hcat [            char '\t',            text "st",            pprFormat fmt,@@ -471,7 +471,7 @@            ]     STC fmt reg1 addr-      -> hcat [+      -> line $ hcat [            text "\tst",            case fmt of              II32 -> char 'w'@@ -484,7 +484,7 @@            ]     LIS reg imm-      -> hcat [+      -> line $ hcat [            char '\t',            text "lis",            char '\t',@@ -494,7 +494,7 @@            ]     LI reg imm-      -> hcat [+      -> line $ hcat [            char '\t',            text "li",            char '\t',@@ -505,7 +505,7 @@     MR reg1 reg2     | reg1 == reg2 -> empty-    | otherwise    -> hcat [+    | otherwise    -> line $ hcat [         char '\t',         case targetClassOfReg platform reg1 of             RcInteger -> text "mr"@@ -517,7 +517,7 @@         ]     CMP fmt reg ri-      -> hcat [+      -> line $ hcat [            char '\t',            op,            char '\t',@@ -535,7 +535,7 @@                ]     CMPL fmt reg ri-      -> hcat [+      -> line $ hcat [            char '\t',            op,            char '\t',@@ -553,7 +553,7 @@                   ]     BCC cond blockid prediction-      -> hcat [+      -> line $ hcat [            char '\t',            text "b",            pprCond cond,@@ -568,7 +568,7 @@                  Just False -> char '-'     BCCFAR cond blockid prediction-      -> vcat [+      -> lines_ [            hcat [                text "\tb",                pprCond (condNegate cond),@@ -590,15 +590,13 @@      -- We never jump to ForeignLabels; if we ever do, c.f. handling for "BL"      | isForeignLabel lbl -> panic "PPC.Ppr.pprInstr: JMP to ForeignLabel"      | otherwise ->-       hcat [ -- an alias for b that takes a CLabel-           char '\t',-           text "b",-           char '\t',+       line $ hcat [ -- an alias for b that takes a CLabel+           text "\tb\t",            pprAsmLabel platform lbl        ]     MTCTR reg-      -> hcat [+      -> line $ hcat [            char '\t',            text "mtctr",            char '\t',@@ -606,7 +604,7 @@         ]     BCTR _ _ _-      -> hcat [+      -> line $ hcat [            char '\t',            text "bctr"          ]@@ -623,18 +621,18 @@              -- but when profiling the codegen inserts calls via              -- 'emitRtsCallGen' which are 'CmmLabel's even though              -- they'd technically be more like 'ForeignLabel's.-             hcat [+             line $ hcat [                text "\tbl\t.",                pprAsmLabel platform lbl              ]            _ ->-             hcat [+             line $ hcat [                text "\tbl\t",                pprAsmLabel platform lbl              ]     BCTRL _-      -> hcat [+      -> line $ hcat [              char '\t',              text "bctrl"          ]@@ -643,7 +641,7 @@       -> pprLogic platform (text "add") reg1 reg2 ri     ADDIS reg1 reg2 imm-      -> hcat [+      -> line $ hcat [            char '\t',            text "addis",            char '\t',@@ -673,7 +671,7 @@       -> pprLogic platform (text "subfo") reg1 reg2 (RIReg reg3)     SUBFC reg1 reg2 ri-      -> hcat [+      -> line $ hcat [            char '\t',            text "subf",            case ri of@@ -694,7 +692,7 @@       -> pprMul platform fmt reg1 reg2 ri     MULLO fmt reg1 reg2 reg3-      -> hcat [+      -> line $ hcat [              char '\t',              text "mull",              case fmt of@@ -711,13 +709,13 @@     MFOV fmt reg       -> vcat [-           hcat [+           line $ hcat [                char '\t',                text "mfxer",                char '\t',                pprReg reg                ],-           hcat [+           line $ hcat [                char '\t',                text "extr",                case fmt of@@ -737,7 +735,7 @@            ]     MULHU fmt reg1 reg2 reg3-      -> hcat [+      -> line $ hcat [             char '\t',             text "mulh",             case fmt of@@ -758,7 +756,7 @@         -- for some reason, "andi" doesn't exist.         -- we'll use "andi." instead.    AND reg1 reg2 (RIImm imm)-      -> hcat [+      -> line $ hcat [             char '\t',             text "andi.",             char '\t',@@ -785,7 +783,7 @@       -> pprLogic platform (text "xor") reg1 reg2 ri     ORIS reg1 reg2 imm-      -> hcat [+      -> line $ hcat [             char '\t',             text "oris",             char '\t',@@ -797,7 +795,7 @@         ]     XORIS reg1 reg2 imm-      -> hcat [+      -> line $ hcat [             char '\t',             text "xoris",             char '\t',@@ -809,7 +807,7 @@         ]     EXTS fmt reg1 reg2-      -> hcat [+      -> line $ hcat [            char '\t',            text "exts",            pprFormat fmt,@@ -820,7 +818,7 @@          ]     CNTLZ fmt reg1 reg2-      -> hcat [+      -> line $ hcat [            char '\t',            text "cntlz",            case fmt of@@ -881,7 +879,7 @@          in pprLogic platform op reg1 reg2 (limitShiftRI fmt ri)     RLWINM reg1 reg2 sh mb me-      -> hcat [+      -> line $ hcat [              text "\trlwinm\t",              pprReg reg1,              text ", ",@@ -895,7 +893,7 @@          ]     CLRLI fmt reg1 reg2 n-      -> hcat [+      -> line $ hcat [             text "\tclrl",             pprFormat fmt,             text "i ",@@ -907,7 +905,7 @@         ]     CLRRI fmt reg1 reg2 n-      -> hcat [+      -> line $ hcat [             text "\tclrr",             pprFormat fmt,             text "i ",@@ -937,7 +935,7 @@       -> pprUnary (text "fneg") reg1 reg2     FCMP reg1 reg2-      -> hcat [+      -> line $ hcat [            char '\t',            text "fcmpu\t0, ",                -- Note: we're using fcmpu, not fcmpo@@ -965,7 +963,7 @@       -> pprUnary (text "frsp") reg1 reg2     CRNOR dst src1 src2-      -> hcat [+      -> line $ hcat [            text "\tcrnor\t",            int dst,            text ", ",@@ -975,7 +973,7 @@          ]     MFCR reg-      -> hcat [+      -> line $ hcat [              char '\t',              text "mfcr",              char '\t',@@ -983,7 +981,7 @@          ]     MFLR reg-      -> hcat [+      -> line $ hcat [            char '\t',            text "mflr",            char '\t',@@ -991,25 +989,25 @@          ]     FETCHPC reg-      -> vcat [+      -> lines_ [              text "\tbcl\t20,31,1f",              hcat [ text "1:\tmflr\t", pprReg reg ]          ]     HWSYNC-      -> text "\tsync"+      -> line $ text "\tsync"     ISYNC-      -> text "\tisync"+      -> line $ text "\tisync"     LWSYNC-      -> text "\tlwsync"+      -> line $ text "\tlwsync"     NOP-      -> text "\tnop"+      -> line $ text "\tnop" -pprLogic :: Platform -> SDoc -> Reg -> Reg -> RI -> SDoc-pprLogic platform op reg1 reg2 ri = hcat [+pprLogic :: IsDoc doc => Platform -> Line doc -> Reg -> Reg -> RI -> doc+pprLogic platform op reg1 reg2 ri = line $ hcat [         char '\t',         op,         case ri of@@ -1024,8 +1022,8 @@     ]  -pprMul :: Platform -> Format -> Reg -> Reg -> RI -> SDoc-pprMul platform fmt reg1 reg2 ri = hcat [+pprMul :: IsDoc doc => Platform -> Format -> Reg -> Reg -> RI -> doc+pprMul platform fmt reg1 reg2 ri = line $ hcat [         char '\t',         text "mull",         case ri of@@ -1043,8 +1041,8 @@     ]  -pprDiv :: Format -> Bool -> Reg -> Reg -> Reg -> SDoc-pprDiv fmt sgn reg1 reg2 reg3 = hcat [+pprDiv :: IsDoc doc => Format -> Bool -> Reg -> Reg -> Reg -> doc+pprDiv fmt sgn reg1 reg2 reg3 = line $ hcat [         char '\t',         text "div",         case fmt of@@ -1061,8 +1059,8 @@     ]  -pprUnary :: SDoc -> Reg -> Reg -> SDoc-pprUnary op reg1 reg2 = hcat [+pprUnary :: IsDoc doc => Line doc -> Reg -> Reg -> doc+pprUnary op reg1 reg2 = line $ hcat [         char '\t',         op,         char '\t',@@ -1072,8 +1070,8 @@     ]  -pprBinaryF :: SDoc -> Format -> Reg -> Reg -> Reg -> SDoc-pprBinaryF op fmt reg1 reg2 reg3 = hcat [+pprBinaryF :: IsDoc doc => Line doc -> Format -> Reg -> Reg -> Reg -> doc+pprBinaryF op fmt reg1 reg2 reg3 = line $ hcat [         char '\t',         op,         pprFFormat fmt,@@ -1085,12 +1083,12 @@         pprReg reg3     ] -pprRI :: Platform -> RI -> SDoc+pprRI :: IsLine doc => Platform -> RI -> doc pprRI _        (RIReg r) = pprReg r pprRI platform (RIImm r) = pprImm platform r  -pprFFormat :: Format -> SDoc+pprFFormat :: IsLine doc => Format -> doc pprFFormat FF64     = empty pprFFormat FF32     = char 's' pprFFormat _        = panic "PPC.Ppr.pprFFormat: no match"
compiler/GHC/CmmToAsm/PPC/Regs.hs view
@@ -47,6 +47,7 @@ where  import GHC.Prelude+import GHC.Data.FastString  import GHC.Platform.Reg import GHC.Platform.Reg.Class@@ -133,7 +134,7 @@         = ImmInt        Int         | ImmInteger    Integer     -- Sigh.         | ImmCLbl       CLabel      -- AbstractC Label (with baggage)-        | ImmLit        String+        | ImmLit        FastString         | ImmIndex    CLabel Int         | ImmFloat      Rational         | ImmDouble     Rational@@ -146,7 +147,7 @@         | HIGHESTA Imm  -strImmLit :: String -> Imm+strImmLit :: FastString -> Imm strImmLit s = ImmLit s  
compiler/GHC/CmmToAsm/Ppr.hs view
@@ -27,7 +27,6 @@ import GHC.Cmm import GHC.CmmToAsm.Config import GHC.Utils.Outputable as SDoc-import qualified GHC.Utils.Ppr as Pretty import GHC.Utils.Panic import GHC.Platform @@ -89,7 +88,7 @@ -- Print as a string and escape non-printable characters. -- This is similar to charToC in GHC.Utils.Misc -pprASCII :: ByteString -> SDoc+pprASCII :: forall doc. IsLine doc => ByteString -> doc pprASCII str   -- Transform this given literal bytestring to escaped string and construct   -- the literal SDoc directly.@@ -98,19 +97,19 @@   --   -- We work with a `Doc` instead of an `SDoc` because there is no need to carry   -- an `SDocContext` that we don't use. It leads to nicer (STG) code.-  = docToSDoc (BS.foldr f Pretty.empty str)+  = BS.foldr f empty str     where-       f :: Word8 -> Pretty.Doc -> Pretty.Doc-       f w s = do1 w Pretty.<> s+       f :: Word8 -> doc -> doc+       f w s = do1 w <> s -       do1 :: Word8 -> Pretty.Doc-       do1 w | 0x09 == w = Pretty.text "\\t"-             | 0x0A == w = Pretty.text "\\n"-             | 0x22 == w = Pretty.text "\\\""-             | 0x5C == w = Pretty.text "\\\\"+       do1 :: Word8 -> doc+       do1 w | 0x09 == w = text "\\t"+             | 0x0A == w = text "\\n"+             | 0x22 == w = text "\\\""+             | 0x5C == w = text "\\\\"                -- ASCII printable characters range-             | w >= 0x20 && w <= 0x7E = Pretty.char (chr' w)-             | otherwise = Pretty.sizedText 4 xs+             | w >= 0x20 && w <= 0x7E = char (chr' w)+             | otherwise = text xs                 where                  !xs = [ '\\', x0, x1, x2] -- octal                  !x0 = chr' (ord0 + (w `unsafeShiftR` 6) .&. 0x07)@@ -122,20 +121,25 @@        -- so we bypass the check in "chr"        chr' :: Word8 -> Char        chr' (W8# w#) = C# (chr# (word2Int# (word8ToWord# w#)))-+{-# SPECIALIZE pprASCII :: ByteString -> SDoc #-}+{-# SPECIALIZE pprASCII :: ByteString -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Emit a ".string" directive-pprString :: ByteString -> SDoc+pprString :: IsLine doc => ByteString -> doc pprString bs = text "\t.string " <> doubleQuotes (pprASCII bs)+{-# SPECIALIZE pprString :: ByteString -> SDoc #-}+{-# SPECIALIZE pprString :: ByteString -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Emit a ".incbin" directive -- -- A NULL byte is added after the binary data.-pprFileEmbed :: FilePath -> SDoc+pprFileEmbed :: IsLine doc => FilePath -> doc pprFileEmbed path    = text "\t.incbin "      <> pprFilePathString path -- proper escape (see #16389)      <> text "\n\t.byte 0"+{-# SPECIALIZE pprFileEmbed :: FilePath -> SDoc #-}+{-# SPECIALIZE pprFileEmbed :: FilePath -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  {- Note [Embedding large binary blobs]@@ -193,14 +197,16 @@ -- identical strings in the linker. With -split-sections each string also gets -- a unique section to allow strings from unused code to be GC'd. -pprSectionHeader :: NCGConfig -> Section -> SDoc+pprSectionHeader :: IsLine doc => NCGConfig -> Section -> doc pprSectionHeader config (Section t suffix) =  case platformOS (ncgPlatform config) of    OSAIX     -> pprXcoffSectionHeader t    OSDarwin  -> pprDarwinSectionHeader t    _         -> pprGNUSectionHeader config t suffix+{-# SPECIALIZE pprSectionHeader :: NCGConfig -> Section -> SDoc #-}+{-# SPECIALIZE pprSectionHeader :: NCGConfig -> Section -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable -pprGNUSectionHeader :: NCGConfig -> SectionType -> CLabel -> SDoc+pprGNUSectionHeader :: IsLine doc => NCGConfig -> SectionType -> CLabel -> doc pprGNUSectionHeader config t suffix =   hcat [text ".section ", header, subsection, flags]   where@@ -244,10 +250,12 @@                     -> empty         | otherwise -> text ",\"aMS\"," <> sectionType platform "progbits" <> text ",1"       _ -> empty+{-# SPECIALIZE pprGNUSectionHeader :: NCGConfig -> SectionType -> CLabel -> SDoc #-}+{-# SPECIALIZE pprGNUSectionHeader :: NCGConfig -> SectionType -> CLabel -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- XCOFF doesn't support relocating label-differences, so we place all -- RO sections into .text[PR] sections-pprXcoffSectionHeader :: SectionType -> SDoc+pprXcoffSectionHeader :: IsLine doc => SectionType -> doc pprXcoffSectionHeader t = case t of   Text                    -> text ".csect .text[PR]"   Data                    -> text ".csect .data[RW]"@@ -256,8 +264,10 @@   CString                 -> text ".csect .text[PR] # CString"   UninitialisedData       -> text ".csect .data[BS]"   _                       -> panic "pprXcoffSectionHeader: unknown section type"+{-# SPECIALIZE pprXcoffSectionHeader :: SectionType -> SDoc #-}+{-# SPECIALIZE pprXcoffSectionHeader :: SectionType -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable -pprDarwinSectionHeader :: SectionType -> SDoc+pprDarwinSectionHeader :: IsLine doc => SectionType -> doc pprDarwinSectionHeader t = case t of   Text                    -> text ".text"   Data                    -> text ".data"@@ -268,3 +278,5 @@   FiniArray               -> panic "pprDarwinSectionHeader: fini not supported"   CString                 -> text ".section\t__TEXT,__cstring,cstring_literals"   OtherSection _          -> panic "pprDarwinSectionHeader: unknown section type"+{-# SPECIALIZE pprDarwinSectionHeader :: SectionType -> SDoc #-}+{-# SPECIALIZE pprDarwinSectionHeader :: SectionType -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
compiler/GHC/CmmToAsm/Reg/Graph/Spill.hs view
@@ -147,8 +147,7 @@                                 $ mapLookup blockId slotMap                  moreSlotsLive   = IntSet.fromList-                                $ catMaybes-                                $ map (lookupUFM regSlotMap)+                                $ mapMaybe (lookupUFM regSlotMap)                                 $ nonDetEltsUniqSet regsLive                     -- See Note [Unique Determinism and code generation] 
compiler/GHC/CmmToAsm/Reg/Graph/SpillClean.hs view
@@ -390,8 +390,7 @@         = do                 let slotsReloadedByTargets                         = IntSet.unions-                        $ catMaybes-                        $ map (flip mapLookup liveSlotsOnEntry)+                        $ mapMaybe (flip mapLookup liveSlotsOnEntry)                         $ targets                  let noReloads'
compiler/GHC/CmmToAsm/Reg/Graph/SpillCost.hs view
@@ -130,8 +130,8 @@                  -- Increment counts for what regs were read/written from.                 let (RU read written)   = regUsageOfInstr platform instr-                mapM_ (incUses scale) $ catMaybes $ map takeVirtualReg $ nub read-                mapM_ (incDefs scale) $ catMaybes $ map takeVirtualReg $ nub written+                mapM_ (incUses scale) $ mapMaybe takeVirtualReg $ nub read+                mapM_ (incDefs scale) $ mapMaybe takeVirtualReg $ nub written                  -- Compute liveness for entry to next instruction.                 let liveDieRead_virt    = takeVirtuals (liveDieRead  live)
compiler/GHC/CmmToAsm/Reg/Graph/TrivColorable.hs view
@@ -119,6 +119,7 @@                             ArchS390X     -> panic "trivColorable ArchS390X"                             ArchRISCV64   -> panic "trivColorable ArchRISCV64"                             ArchJavaScript-> panic "trivColorable ArchJavaScript"+                            ArchWasm32    -> panic "trivColorable ArchWasm32"                             ArchUnknown   -> panic "trivColorable ArchUnknown")         , count2        <- accSqueeze 0 cALLOCATABLE_REGS_INTEGER                                 (virtualRegSqueeze RcInteger)@@ -152,6 +153,7 @@                             ArchS390X     -> panic "trivColorable ArchS390X"                             ArchRISCV64   -> panic "trivColorable ArchRISCV64"                             ArchJavaScript-> panic "trivColorable ArchJavaScript"+                            ArchWasm32    -> panic "trivColorable ArchWasm32"                             ArchUnknown   -> panic "trivColorable ArchUnknown")         , count2        <- accSqueeze 0 cALLOCATABLE_REGS_FLOAT                                 (virtualRegSqueeze RcFloat)@@ -184,6 +186,7 @@                             ArchS390X     -> panic "trivColorable ArchS390X"                             ArchRISCV64   -> panic "trivColorable ArchRISCV64"                             ArchJavaScript-> panic "trivColorable ArchJavaScript"+                            ArchWasm32    -> panic "trivColorable ArchWasm32"                             ArchUnknown   -> panic "trivColorable ArchUnknown")         , count2        <- accSqueeze 0 cALLOCATABLE_REGS_DOUBLE                                 (virtualRegSqueeze RcDouble)
compiler/GHC/CmmToAsm/Reg/Linear.hs view
@@ -225,6 +225,7 @@       ArchMipsel     -> panic "linearRegAlloc ArchMipsel"       ArchRISCV64    -> panic "linearRegAlloc ArchRISCV64"       ArchJavaScript -> panic "linearRegAlloc ArchJavaScript"+      ArchWasm32     -> panic "linearRegAlloc ArchWasm32"       ArchUnknown    -> panic "linearRegAlloc ArchUnknown"  where   go :: (FR regs, Outputable regs)
compiler/GHC/CmmToAsm/Reg/Linear/FreeRegs.hs view
@@ -78,4 +78,5 @@    ArchMipsel    -> panic "maxSpillSlots ArchMipsel"    ArchRISCV64   -> panic "maxSpillSlots ArchRISCV64"    ArchJavaScript-> panic "maxSpillSlots ArchJavaScript"+   ArchWasm32    -> panic "maxSpillSlots ArchWasm32"    ArchUnknown   -> panic "maxSpillSlots ArchUnknown"
compiler/GHC/CmmToAsm/Reg/Linear/JoinToTargets.hs view
@@ -31,6 +31,8 @@ import GHC.Types.Unique.FM import GHC.Types.Unique.Set +import GHC.Utils.Outputable+ -- | For a jump instruction at the end of a block, generate fixup code so its --      vregs are in the correct regs for its destination. --@@ -375,6 +377,5 @@               -- we don't handle memory to memory moves.               -- they shouldn't happen because we don't share               -- stack slots between vregs.-              panic ("makeMove " ++ show vreg ++ " (" ++ show src ++ ") ("-                  ++ show dst ++ ")"-                  ++ " we don't handle mem->mem moves.")+              pprPanic "makeMove: we don't handle mem->mem moves"+                 (ppr vreg <+> parens (ppr src) <+> parens (ppr dst))
compiler/GHC/CmmToAsm/Reg/Target.hs view
@@ -51,6 +51,7 @@       ArchMipsel    -> panic "targetVirtualRegSqueeze ArchMipsel"       ArchRISCV64   -> panic "targetVirtualRegSqueeze ArchRISCV64"       ArchJavaScript-> panic "targetVirtualRegSqueeze ArchJavaScript"+      ArchWasm32    -> panic "targetVirtualRegSqueeze ArchWasm32"       ArchUnknown   -> panic "targetVirtualRegSqueeze ArchUnknown"  @@ -69,6 +70,7 @@       ArchMipsel    -> panic "targetRealRegSqueeze ArchMipsel"       ArchRISCV64   -> panic "targetRealRegSqueeze ArchRISCV64"       ArchJavaScript-> panic "targetRealRegSqueeze ArchJavaScript"+      ArchWasm32    -> panic "targetRealRegSqueeze ArchWasm32"       ArchUnknown   -> panic "targetRealRegSqueeze ArchUnknown"  targetClassOfRealReg :: Platform -> RealReg -> RegClass@@ -86,6 +88,7 @@       ArchMipsel    -> panic "targetClassOfRealReg ArchMipsel"       ArchRISCV64   -> panic "targetClassOfRealReg ArchRISCV64"       ArchJavaScript-> panic "targetClassOfRealReg ArchJavaScript"+      ArchWasm32    -> panic "targetClassOfRealReg ArchWasm32"       ArchUnknown   -> panic "targetClassOfRealReg ArchUnknown"  targetMkVirtualReg :: Platform -> Unique -> Format -> VirtualReg@@ -103,6 +106,7 @@       ArchMipsel    -> panic "targetMkVirtualReg ArchMipsel"       ArchRISCV64   -> panic "targetMkVirtualReg ArchRISCV64"       ArchJavaScript-> panic "targetMkVirtualReg ArchJavaScript"+      ArchWasm32    -> panic "targetMkVirtualReg ArchWasm32"       ArchUnknown   -> panic "targetMkVirtualReg ArchUnknown"  targetRegDotColor :: Platform -> RealReg -> SDoc@@ -120,6 +124,7 @@       ArchMipsel    -> panic "targetRegDotColor ArchMipsel"       ArchRISCV64   -> panic "targetRegDotColor ArchRISCV64"       ArchJavaScript-> panic "targetRegDotColor ArchJavaScript"+      ArchWasm32    -> panic "targetRegDotColor ArchWasm32"       ArchUnknown   -> panic "targetRegDotColor ArchUnknown"  
+ compiler/GHC/CmmToAsm/Wasm.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Strict #-}++module GHC.CmmToAsm.Wasm (ncgWasm) where++import Data.ByteString.Builder+import Data.Maybe+import Data.Semigroup+import GHC.Cmm+import GHC.CmmToAsm.Wasm.Asm+import GHC.CmmToAsm.Wasm.FromCmm+import GHC.CmmToAsm.Wasm.Types+import GHC.Data.Stream (Stream, StreamS (..), runStream)+import GHC.Platform+import GHC.Prelude+import GHC.Types.Unique.Supply+import GHC.Unit+import System.IO++ncgWasm ::+  Platform ->+  UniqSupply ->+  ModLocation ->+  Handle ->+  Stream IO RawCmmGroup a ->+  IO a+ncgWasm platform us loc h cmms = do+  (r, s) <- streamCmmGroups platform us cmms+  hPutBuilder h $ "# " <> string7 (fromJust $ ml_hs_file loc) <> "\n\n"+  hPutBuilder h $ execWasmAsmM $ asmTellEverything TagI32 s+  pure r++streamCmmGroups ::+  Platform ->+  UniqSupply ->+  Stream IO RawCmmGroup a ->+  IO (a, WasmCodeGenState 'I32)+streamCmmGroups platform us cmms =+  go (initialWasmCodeGenState platform us) $+    runStream cmms+  where+    go s (Done r) = pure (r, s)+    go s (Effect m) = m >>= go s+    go s (Yield cmm k) = go (wasmExecM (onCmmGroup cmm) s) k
+ compiler/GHC/CmmToAsm/Wasm/Asm.hs view
@@ -0,0 +1,511 @@+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE Strict #-}++module GHC.CmmToAsm.Wasm.Asm (asmTellEverything, execWasmAsmM) where++import Control.Monad+import Control.Monad.Trans.Reader+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import Data.ByteString.Builder+import Data.Coerce+import Data.Foldable+import qualified Data.IntSet as IS+import Data.Maybe+import Data.Semigroup+import GHC.Cmm+import GHC.CmmToAsm.Ppr+import GHC.CmmToAsm.Wasm.FromCmm+import GHC.CmmToAsm.Wasm.Types+import GHC.CmmToAsm.Wasm.Utils+import GHC.Data.FastString+import GHC.Float+import GHC.Prelude+import GHC.Types.Basic+import GHC.Types.Unique+import GHC.Types.Unique.Map+import GHC.Utils.Monad.State.Strict+import GHC.Utils.Outputable hiding ((<>))+import GHC.Utils.Panic (panic)++-- | Reads current indentation, appends result to state+newtype WasmAsmM a = WasmAsmM (Builder -> State Builder a)+  deriving+    ( Functor,+      Applicative,+      Monad+    )+    via (ReaderT Builder (State Builder))++instance Semigroup a => Semigroup (WasmAsmM a) where+  (<>) = liftA2 (<>)++instance Monoid a => Monoid (WasmAsmM a) where+  mempty = pure mempty++-- | Default indent level is none+execWasmAsmM :: WasmAsmM a -> Builder+execWasmAsmM (WasmAsmM m) = execState (m mempty) mempty++-- | Increase indent level by a tab+asmWithTab :: WasmAsmM a -> WasmAsmM a+asmWithTab (WasmAsmM m) = WasmAsmM $ \t -> m $! char7 '\t' <> t++-- | Writes a single line starting with the current indent+asmTellLine :: Builder -> WasmAsmM ()+asmTellLine b = WasmAsmM $ \t -> modify $ \acc -> acc <> t <> b <> char7 '\n'++-- | Writes a single line break+asmTellLF :: WasmAsmM ()+asmTellLF = WasmAsmM $ \_ -> modify $ \acc -> acc <> char7 '\n'++-- | Writes a line starting with a single tab, ignoring current indent+-- level+asmTellTabLine :: Builder -> WasmAsmM ()+asmTellTabLine b =+  WasmAsmM $ \_ -> modify $ \acc -> acc <> char7 '\t' <> b <> char7 '\n'++asmFromWasmType :: WasmTypeTag t -> Builder+asmFromWasmType ty = case ty of+  TagI32 -> "i32"+  TagI64 -> "i64"+  TagF32 -> "f32"+  TagF64 -> "f64"++asmFromSomeWasmType :: SomeWasmType -> Builder+asmFromSomeWasmType (SomeWasmType t) = asmFromWasmType t++asmFromSomeWasmTypes :: [SomeWasmType] -> Builder+asmFromSomeWasmTypes ts = "(" <> builderCommas asmFromSomeWasmType ts <> ")"++asmFromFuncType :: [SomeWasmType] -> [SomeWasmType] -> Builder+asmFromFuncType arg_tys ret_tys =+  asmFromSomeWasmTypes arg_tys <> " -> " <> asmFromSomeWasmTypes ret_tys++asmTellFuncType ::+  SymName -> ([SomeWasmType], [SomeWasmType]) -> WasmAsmM ()+asmTellFuncType sym (arg_tys, ret_tys) =+  asmTellTabLine $+    ".functype "+      <> asmFromSymName sym+      <> " "+      <> asmFromFuncType arg_tys ret_tys++asmTellLocals :: [SomeWasmType] -> WasmAsmM ()+asmTellLocals [] = mempty+asmTellLocals local_tys =+  asmTellTabLine $ ".local " <> builderCommas asmFromSomeWasmType local_tys++asmFromSymName :: SymName -> Builder+asmFromSymName = shortByteString . coerce fastStringToShortByteString++asmTellDefSym :: SymName -> WasmAsmM ()+asmTellDefSym sym = do+  asmTellTabLine $ ".hidden " <> asm_sym+  asmTellTabLine $ ".globl " <> asm_sym+  where+    asm_sym = asmFromSymName sym++asmTellDataSectionContent :: WasmTypeTag w -> DataSectionContent -> WasmAsmM ()+asmTellDataSectionContent ty_word c = asmTellTabLine $ case c of+  DataI8 i -> ".int8 " <> integerDec i+  DataI16 i -> ".int16 " <> integerDec i+  DataI32 i -> ".int32 " <> integerDec i+  DataI64 i -> ".int64 " <> integerDec i+  DataF32 f -> ".int32 0x" <> word32Hex (castFloatToWord32 f)+  DataF64 d -> ".int64 0x" <> word64Hex (castDoubleToWord64 d)+  DataSym sym o ->+    ( case ty_word of+        TagI32 -> ".int32 "+        TagI64 -> ".int64 "+        _ -> panic "asmTellDataSectionContent: unreachable"+    )+      <> asmFromSymName sym+      <> ( case compare o 0 of+             EQ -> mempty+             GT -> "+" <> intDec o+             LT -> intDec o+         )+  DataSkip i -> ".skip " <> intDec i+  DataASCII s+    | not (BS.null s) && BS.last s == 0 ->+        ".asciz \""+          <> string7+            (showSDocOneLine defaultSDocContext $ pprASCII $ BS.init s)+          <> "\""+    | otherwise ->+        ".ascii \""+          <> string7+            (showSDocOneLine defaultSDocContext $ pprASCII s)+          <> "\""+  DataIncBin f _ ->+    ".incbin "+      <> string7+        (showSDocOneLine defaultSDocContext $ pprFilePathString f)++dataSectionContentSize :: WasmTypeTag w -> DataSectionContent -> Int+dataSectionContentSize ty_word c = case c of+  DataI8 {} -> 1+  DataI16 {} -> 2+  DataI32 {} -> 4+  DataI64 {} -> 8+  DataF32 {} -> 4+  DataF64 {} -> 8+  DataSym {} -> alignmentBytes $ alignmentFromWordType ty_word+  DataSkip i -> i+  DataASCII s -> BS.length s+  DataIncBin _ l -> l++dataSectionSize :: WasmTypeTag w -> [DataSectionContent] -> Int+dataSectionSize ty_word =+  coerce+    . foldMap'+      (Sum . dataSectionContentSize ty_word)++asmTellAlign :: Alignment -> WasmAsmM ()+asmTellAlign a = case alignmentBytes a of+  1 -> mempty+  i -> asmTellTabLine $ ".p2align " <> intDec (countTrailingZeros i)++asmTellSectionHeader :: Builder -> WasmAsmM ()+asmTellSectionHeader k = asmTellTabLine $ ".section " <> k <> ",\"\",@"++asmTellDataSection ::+  WasmTypeTag w -> IS.IntSet -> SymName -> DataSection -> WasmAsmM ()+asmTellDataSection ty_word def_syms sym DataSection {..} = do+  when (getKey (getUnique sym) `IS.member` def_syms) $ asmTellDefSym sym+  asmTellSectionHeader sec_name+  asmTellAlign dataSectionAlignment+  asmTellTabLine asm_size+  asmTellLine $ asm_sym <> ":"+  for_ dataSectionContents $ asmTellDataSectionContent ty_word+  asmTellLF+  where+    asm_sym = asmFromSymName sym++    sec_name =+      ( case dataSectionKind of+          SectionData -> ".data."+          SectionROData -> ".rodata."+      )+        <> asm_sym++    asm_size =+      ".size "+        <> asm_sym+        <> ", "+        <> intDec+          (dataSectionSize ty_word dataSectionContents)++asmFromWasmBlockType :: WasmTypeTag w -> WasmFunctionType pre post -> Builder+asmFromWasmBlockType+  _+  (WasmFunctionType {ft_pops = TypeListNil, ft_pushes = TypeListNil}) =+    mempty+asmFromWasmBlockType+  TagI32+  ( WasmFunctionType+      { ft_pops = TypeListNil,+        ft_pushes = TypeListCons TagI32 TypeListNil+      }+    ) =+    " i32"+asmFromWasmBlockType+  TagI64+  ( WasmFunctionType+      { ft_pops = TypeListNil,+        ft_pushes = TypeListCons TagI64 TypeListNil+      }+    ) =+    " i64"+asmFromWasmBlockType _ _ = panic "asmFromWasmBlockType: invalid block type"++asmFromAlignmentSpec :: AlignmentSpec -> Builder+asmFromAlignmentSpec NaturallyAligned = mempty+asmFromAlignmentSpec Unaligned = ":p2align=0"++asmTellWasmInstr :: WasmTypeTag w -> WasmInstr w pre post -> WasmAsmM ()+asmTellWasmInstr ty_word instr = case instr of+  WasmComment c -> asmTellLine $ stringUtf8 $ "# " <> c+  WasmNop -> mempty+  WasmDrop -> asmTellLine "drop"+  WasmUnreachable -> asmTellLine "unreachable"+  WasmConst TagI32 i -> asmTellLine $ "i32.const " <> integerDec i+  WasmConst TagI64 i -> asmTellLine $ "i64.const " <> integerDec i+  WasmConst {} -> panic "asmTellWasmInstr: unreachable"+  WasmSymConst sym ->+    asmTellLine $+      ( case ty_word of+          TagI32 -> "i32.const "+          TagI64 -> "i64.const "+          _ -> panic "asmTellWasmInstr: unreachable"+      )+        <> asmFromSymName sym+  WasmLoad ty (Just w) s o align ->+    asmTellLine $+      asmFromWasmType ty+        <> ".load"+        <> intDec w+        <> ( case s of+               Signed -> "_s"+               Unsigned -> "_u"+           )+        <> " "+        <> intDec o+        <> asmFromAlignmentSpec align+  WasmLoad ty Nothing _ o align ->+    asmTellLine $+      asmFromWasmType ty+        <> ".load"+        <> " "+        <> intDec o+        <> asmFromAlignmentSpec align+  WasmStore ty (Just w) o align ->+    asmTellLine $+      asmFromWasmType ty+        <> ".store"+        <> intDec w+        <> " "+        <> intDec o+        <> asmFromAlignmentSpec align+  WasmStore ty Nothing o align ->+    asmTellLine $+      asmFromWasmType ty+        <> ".store"+        <> " "+        <> intDec o+        <> asmFromAlignmentSpec align+  WasmGlobalGet _ sym -> asmTellLine $ "global.get " <> asmFromSymName sym+  WasmGlobalSet _ sym -> asmTellLine $ "global.set " <> asmFromSymName sym+  WasmLocalGet _ i -> asmTellLine $ "local.get " <> intDec i+  WasmLocalSet _ i -> asmTellLine $ "local.set " <> intDec i+  WasmLocalTee _ i -> asmTellLine $ "local.tee " <> intDec i+  WasmCCall sym -> asmTellLine $ "call " <> asmFromSymName sym+  WasmCCallIndirect arg_tys ret_tys ->+    asmTellLine $+      "call_indirect "+        <> asmFromFuncType+          (someWasmTypesFromTypeList arg_tys)+          (someWasmTypesFromTypeList ret_tys)+  WasmConcat instr0 instr1 -> do+    asmTellWasmInstr ty_word instr0+    asmTellWasmInstr ty_word instr1+  WasmReinterpret t0 t1 ->+    asmTellLine $+      asmFromWasmType t1 <> ".reinterpret_" <> asmFromWasmType t0+  WasmTruncSat Signed t0 t1 ->+    asmTellLine $+      asmFromWasmType t1 <> ".trunc_sat_" <> asmFromWasmType t0 <> "_s"+  WasmTruncSat Unsigned t0 t1 ->+    asmTellLine $+      asmFromWasmType t1 <> ".trunc_sat_" <> asmFromWasmType t0 <> "_u"+  WasmConvert Signed t0 t1 ->+    asmTellLine $+      asmFromWasmType t1 <> ".convert_" <> asmFromWasmType t0 <> "_s"+  WasmConvert Unsigned t0 t1 ->+    asmTellLine $+      asmFromWasmType t1 <> ".convert_" <> asmFromWasmType t0 <> "_u"+  WasmAdd ty -> asmTellLine $ asmFromWasmType ty <> ".add"+  WasmSub ty -> asmTellLine $ asmFromWasmType ty <> ".sub"+  WasmMul ty -> asmTellLine $ asmFromWasmType ty <> ".mul"+  WasmDiv _ TagF32 -> asmTellLine "f32.div"+  WasmDiv _ TagF64 -> asmTellLine "f64.div"+  WasmDiv Signed ty -> asmTellLine $ asmFromWasmType ty <> ".div_s"+  WasmDiv Unsigned ty -> asmTellLine $ asmFromWasmType ty <> ".div_u"+  WasmRem Signed ty -> asmTellLine $ asmFromWasmType ty <> ".rem_s"+  WasmRem Unsigned ty -> asmTellLine $ asmFromWasmType ty <> ".rem_u"+  WasmAnd ty -> asmTellLine $ asmFromWasmType ty <> ".and"+  WasmOr ty -> asmTellLine $ asmFromWasmType ty <> ".or"+  WasmXor ty -> asmTellLine $ asmFromWasmType ty <> ".xor"+  WasmEq ty -> asmTellLine $ asmFromWasmType ty <> ".eq"+  WasmNe ty -> asmTellLine $ asmFromWasmType ty <> ".ne"+  WasmLt _ TagF32 -> asmTellLine "f32.lt"+  WasmLt _ TagF64 -> asmTellLine "f64.lt"+  WasmLt Signed ty -> asmTellLine $ asmFromWasmType ty <> ".lt_s"+  WasmLt Unsigned ty -> asmTellLine $ asmFromWasmType ty <> ".lt_u"+  WasmGt _ TagF32 -> asmTellLine "f32.gt"+  WasmGt _ TagF64 -> asmTellLine "f64.gt"+  WasmGt Signed ty -> asmTellLine $ asmFromWasmType ty <> ".gt_s"+  WasmGt Unsigned ty -> asmTellLine $ asmFromWasmType ty <> ".gt_u"+  WasmLe _ TagF32 -> asmTellLine "f32.le"+  WasmLe _ TagF64 -> asmTellLine "f64.le"+  WasmLe Signed ty -> asmTellLine $ asmFromWasmType ty <> ".le_s"+  WasmLe Unsigned ty -> asmTellLine $ asmFromWasmType ty <> ".le_u"+  WasmGe _ TagF32 -> asmTellLine "f32.ge"+  WasmGe _ TagF64 -> asmTellLine "f64.ge"+  WasmGe Signed ty -> asmTellLine $ asmFromWasmType ty <> ".ge_s"+  WasmGe Unsigned ty -> asmTellLine $ asmFromWasmType ty <> ".ge_u"+  WasmShl ty -> asmTellLine $ asmFromWasmType ty <> ".shl"+  WasmShr Signed ty -> asmTellLine $ asmFromWasmType ty <> ".shr_s"+  WasmShr Unsigned ty -> asmTellLine $ asmFromWasmType ty <> ".shr_u"+  WasmI32Extend8S -> asmTellLine "i32.extend8_s"+  WasmI32Extend16S -> asmTellLine "i32.extend16_s"+  WasmI64Extend8S -> asmTellLine "i64.extend8_s"+  WasmI64Extend16S -> asmTellLine "i64.extend16_s"+  WasmI64Extend32S -> asmTellLine "i64.extend32_s"+  WasmI64ExtendI32 Signed -> asmTellLine "i64.extend_i32_s"+  WasmI64ExtendI32 Unsigned -> asmTellLine "i64.extend_i32_u"+  WasmI32WrapI64 -> asmTellLine "i32.wrap_i64"+  WasmF32DemoteF64 -> asmTellLine "f32.demote_f64"+  WasmF64PromoteF32 -> asmTellLine "f64.promote_f32"+  WasmAbs ty -> asmTellLine $ asmFromWasmType ty <> ".abs"+  WasmCond t -> do+    asmTellLine "if"+    asmWithTab $ asmTellWasmInstr ty_word t+    asmTellLine "end_if"++asmTellWasmControl ::+  WasmTypeTag w ->+  WasmControl+    (WasmStatements w)+    (WasmExpr w a)+    pre+    post ->+  WasmAsmM ()+asmTellWasmControl ty_word c = case c of+  WasmPush _ (WasmExpr e) -> asmTellWasmInstr ty_word e+  WasmBlock bt c -> do+    asmTellLine $ "block" <> asmFromWasmBlockType ty_word bt+    asmWithTab $ asmTellWasmControl ty_word c+    asmTellLine "end_block"+  WasmLoop bt c -> do+    asmTellLine $ "loop" <> asmFromWasmBlockType ty_word bt+    asmWithTab $ asmTellWasmControl ty_word c+    -- asmTellLine "br 0"+    asmTellLine "end_loop"+  WasmIfTop bt t f -> do+    asmTellLine $ "if" <> asmFromWasmBlockType ty_word bt+    asmWithTab $ asmTellWasmControl ty_word t+    asmTellLine "else"+    asmWithTab $ asmTellWasmControl ty_word f+    asmTellLine "end_if"+  WasmBr i -> asmTellLine $ "br " <> intDec i+  WasmFallthrough -> mempty+  WasmBrTable (WasmExpr e) _ ts t -> do+    asmTellWasmInstr ty_word e+    asmTellLine $ "br_table {" <> builderCommas intDec (ts <> [t]) <> "}"+  WasmReturnTop _ -> asmTellLine "return"+  WasmActions (WasmStatements a) -> asmTellWasmInstr ty_word a+  WasmSeq c0 c1 -> do+    asmTellWasmControl ty_word c0+    asmTellWasmControl ty_word c1++asmTellFunc ::+  WasmTypeTag w ->+  IS.IntSet ->+  SymName ->+  (([SomeWasmType], [SomeWasmType]), FuncBody w) ->+  WasmAsmM ()+asmTellFunc ty_word def_syms sym (func_ty, FuncBody {..}) = do+  when (getKey (getUnique sym) `IS.member` def_syms) $ asmTellDefSym sym+  asmTellSectionHeader $ ".text." <> asm_sym+  asmTellLine $ asm_sym <> ":"+  asmTellFuncType sym func_ty+  asmTellLocals funcLocals+  asmWithTab $ asmTellWasmControl ty_word funcBody+  asmTellTabLine "end_function"+  asmTellLF+  where+    asm_sym = asmFromSymName sym++asmTellGlobals :: WasmTypeTag w -> WasmAsmM ()+asmTellGlobals ty_word = do+  for_ supportedCmmGlobalRegs $ \reg ->+    let (sym, ty) = fromJust $ globalInfoFromCmmGlobalReg ty_word reg+     in asmTellTabLine $+          ".globaltype "+            <> asmFromSymName sym+            <> ", "+            <> asmFromSomeWasmType ty+  asmTellLF++asmTellCtors :: WasmTypeTag w -> [SymName] -> WasmAsmM ()+asmTellCtors _ [] = mempty+asmTellCtors ty_word syms = do+  asmTellSectionHeader ".init_array"+  asmTellAlign $ alignmentFromWordType ty_word+  for_ syms $ \sym ->+    asmTellTabLine $+      ( case ty_word of+          TagI32 -> ".int32 "+          TagI64 -> ".int64 "+          _ -> panic "asmTellCtors: unreachable"+      )+        <> asmFromSymName sym+  asmTellLF++asmTellBS :: ByteString -> WasmAsmM ()+asmTellBS s = do+  asmTellTabLine $ ".int8 " <> intDec (BS.length s)+  asmTellTabLine $+    ".ascii \""+      <> string7+        (showSDocOneLine defaultSDocContext $ pprASCII s)+      <> "\""++asmTellVec :: [WasmAsmM ()] -> WasmAsmM ()+asmTellVec xs = do+  asmTellTabLine $ ".int8 " <> intDec (length xs)+  sequence_ xs++asmTellProducers :: WasmAsmM ()+asmTellProducers = do+  asmTellSectionHeader ".custom_section.producers"+  asmTellVec+    [ do+        asmTellBS "processed-by"+        asmTellVec+          [ do+              asmTellBS "ghc"+              asmTellBS "9.6"+          ]+    ]++asmTellTargetFeatures :: WasmAsmM ()+asmTellTargetFeatures = do+  asmTellSectionHeader ".custom_section.target_features"+  asmTellVec+    [ do+        asmTellTabLine ".int8 0x2b"+        asmTellBS feature+      | feature <-+          [ "bulk-memory",+            "mutable-globals",+            "nontrapping-fptoint",+            "reference-types",+            "sign-ext"+          ]+    ]++asmTellEverything :: WasmTypeTag w -> WasmCodeGenState w -> WasmAsmM ()+asmTellEverything ty_word WasmCodeGenState {..} = do+  asmTellGlobals ty_word+  asm_functypes+  asm_funcs+  asm_data_secs+  asm_ctors+  asmTellProducers+  asmTellTargetFeatures+  where+    asm_functypes = do+      for_+        (detEltsUniqMap $ funcTypes `minusUniqMap` funcBodies)+        (uncurry asmTellFuncType)+      asmTellLF++    asm_funcs = do+      for_+        (detEltsUniqMap $ intersectUniqMap_C (,) funcTypes funcBodies)+        (uncurry $ asmTellFunc ty_word defaultSyms)+      asmTellLF++    asm_data_secs = do+      for_+        (detEltsUniqMap dataSections)+        (uncurry (asmTellDataSection ty_word defaultSyms))+      asmTellLF++    asm_ctors = asmTellCtors ty_word ctors
+ compiler/GHC/CmmToAsm/Wasm/FromCmm.hs view
@@ -0,0 +1,1677 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE Strict #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}++{-# HLINT ignore "Use camelCase" #-}+module GHC.CmmToAsm.Wasm.FromCmm where++import Control.Monad+import qualified Data.ByteString as BS+import Data.Foldable+import Data.Functor+import qualified Data.IntSet as IS+import Data.Semigroup+import Data.String+import Data.Traversable+import Data.Type.Equality+import GHC.Cmm+import GHC.Cmm.CLabel+import GHC.Cmm.Dataflow.Block+import GHC.Cmm.Dataflow.Label+import GHC.Cmm.InitFini+import GHC.CmmToAsm.Wasm.Types+import GHC.CmmToAsm.Wasm.Utils+import GHC.Float+import GHC.Platform+import GHC.Prelude+import GHC.StgToCmm.CgUtils+import GHC.Types.Basic+import GHC.Types.ForeignCall+import GHC.Types.Unique+import GHC.Types.Unique.FM+import GHC.Types.Unique.Map+import GHC.Utils.Outputable hiding ((<>))+import GHC.Utils.Panic+import GHC.Wasm.ControlFlow.FromCmm++-- | Calculate the wasm representation type from a 'CmmType'. This is+-- a lossy conversion, and sometimes we need to pass the original+-- 'CmmType' or at least its 'Width' around, so to properly add+-- subword truncation or extension logic.+someWasmTypeFromCmmType :: CmmType -> SomeWasmType+someWasmTypeFromCmmType t+  | isWord32 t = SomeWasmType TagI32+  | isWord64 t = SomeWasmType TagI64+  | t `cmmEqType` b16 = SomeWasmType TagI32+  | t `cmmEqType` b8 = SomeWasmType TagI32+  | isFloat64 t = SomeWasmType TagF64+  | isFloat32 t = SomeWasmType TagF32+  | otherwise =+      panic $+        "someWasmTypeFromCmmType: unsupported CmmType "+          <> showSDocOneLine defaultSDocContext (ppr t)++-- | Calculate the optional memory narrowing of a 'CmmLoad' or+-- 'CmmStore'.+wasmMemoryNarrowing :: WasmTypeTag t -> CmmType -> Maybe Int+wasmMemoryNarrowing ty ty_cmm = case (# ty, typeWidth ty_cmm #) of+  (# TagI32, W8 #) -> Just 8+  (# TagI32, W16 #) -> Just 16+  (# TagI32, W32 #) -> Nothing+  (# TagI64, W8 #) -> Just 8+  (# TagI64, W16 #) -> Just 16+  (# TagI64, W32 #) -> Just 32+  (# TagI64, W64 #) -> Nothing+  (# TagF32, W32 #) -> Nothing+  (# TagF64, W64 #) -> Nothing+  _ -> panic "wasmMemoryNarrowing: unreachable"++-- | Despite this is used by the WebAssembly native codegen, we use+-- 'pprCLabel' instead of 'pprAsmLabel' when emitting the textual+-- symbol name. Either one would work, but 'pprCLabel' makes the+-- output assembly code looks closer to the unregisterised codegen+-- output, which can be handy when using the unregisterised codegen as+-- a source of truth when debugging the native codegen.+symNameFromCLabel :: CLabel -> SymName+symNameFromCLabel lbl =+  fromString $+    showSDocOneLine defaultSDocContext {sdocStyle = PprCode} $+      pprCLabel genericPlatform lbl++-- | Calculate a symbol's visibility.+symVisibilityFromCLabel :: CLabel -> SymVisibility+symVisibilityFromCLabel lbl+  | externallyVisibleCLabel lbl = SymDefault+  | otherwise = SymStatic++-- | Calculate a symbol's kind, see haddock docs of 'SymKind' for more+-- explanation.+symKindFromCLabel :: CLabel -> SymKind+symKindFromCLabel lbl+  | isCFunctionLabel lbl = SymFunc+  | otherwise = SymData++-- | Calculate a data section's kind, see haddock docs of+-- 'DataSectionKind' for more explanation.+dataSectionKindFromCmmSection :: Section -> DataSectionKind+dataSectionKindFromCmmSection s = case sectionProtection s of+  ReadWriteSection -> SectionData+  _ -> SectionROData++-- | Calculate the natural alignment size given the platform word+-- type.+alignmentFromWordType :: WasmTypeTag w -> Alignment+alignmentFromWordType TagI32 = mkAlignment 4+alignmentFromWordType TagI64 = mkAlignment 8+alignmentFromWordType _ = panic "alignmentFromWordType: unreachable"++-- | Calculate a data section's alignment. Closures needs to be+-- naturally aligned; info tables need to align to 2, so to get 1 tag+-- bit as forwarding pointer marker. The rest have no alignment+-- requirements.+alignmentFromCmmSection :: WasmTypeTag w -> CLabel -> Alignment+alignmentFromCmmSection t lbl+  | isStaticClosureLabel lbl = alignmentFromWordType t+  | isInfoTableLabel lbl = mkAlignment 2+  | otherwise = mkAlignment 1++-- | Lower a 'CmmStatic'.+lower_CmmStatic :: CmmStatic -> WasmCodeGenM w DataSectionContent+lower_CmmStatic s = case s of+  CmmStaticLit (CmmInt i W8) -> pure $ DataI8 $ naturalNarrowing W8 i+  CmmStaticLit (CmmInt i W16) -> pure $ DataI16 $ naturalNarrowing W16 i+  CmmStaticLit (CmmInt i W32) -> pure $ DataI32 $ naturalNarrowing W32 i+  CmmStaticLit (CmmInt i W64) -> pure $ DataI64 $ naturalNarrowing W64 i+  CmmStaticLit (CmmFloat f W32) -> pure $ DataF32 $ fromRational f+  CmmStaticLit (CmmFloat d W64) -> pure $ DataF64 $ fromRational d+  CmmStaticLit (CmmLabel lbl) ->+    onAnySym lbl+      $> DataSym+        (symNameFromCLabel lbl)+        0+  CmmStaticLit (CmmLabelOff lbl o) ->+    onAnySym lbl+      $> DataSym+        (symNameFromCLabel lbl)+        o+  CmmUninitialised i -> pure $ DataSkip i+  CmmString b -> pure $ DataASCII b+  CmmFileEmbed f l -> pure $ DataIncBin f l+  _ -> panic "lower_CmmStatic: unreachable"++{-+Note [Register mapping on WebAssembly]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Unlike typical ISAs, WebAssembly doesn't expose a fixed set of+registers. For now, we map each Cmm LocalReg to a wasm local, and each+Cmm GlobalReg to a wasm global. The wasm globals are defined in+rts/wasm/Wasm.S, and must be kept in sync with+'globalInfoFromCmmGlobalReg' and 'supportedCmmGlobalRegs' here.++There are some other Cmm GlobalRegs which are still represented by+StgRegTable fields instead of wasm globals (e.g. HpAlloc). It's cheap+to add wasm globals, but other parts of rts logic only work with the+StgRegTable fields, so we also need to instrument StgRun/StgReturn to+sync the wasm globals with the StgRegTable. It's not really worth the+trouble.++-}+globalInfoFromCmmGlobalReg :: WasmTypeTag w -> GlobalReg -> Maybe GlobalInfo+globalInfoFromCmmGlobalReg t reg = case reg of+  VanillaReg i _+    | i >= 1 && i <= 10 -> Just (fromString $ "__R" <> show i, ty_word)+  FloatReg i+    | i >= 1 && i <= 6 ->+        Just (fromString $ "__F" <> show i, SomeWasmType TagF32)+  DoubleReg i+    | i >= 1 && i <= 6 ->+        Just (fromString $ "__D" <> show i, SomeWasmType TagF64)+  LongReg i+    | i == 1 -> Just (fromString $ "__L" <> show i, SomeWasmType TagI64)+  Sp -> Just ("__Sp", ty_word)+  SpLim -> Just ("__SpLim", ty_word)+  Hp -> Just ("__Hp", ty_word)+  HpLim -> Just ("__HpLim", ty_word)+  CCCS -> Just ("__CCCS", ty_word)+  _ -> Nothing+  where+    ty_word = SomeWasmType t++supportedCmmGlobalRegs :: [GlobalReg]+supportedCmmGlobalRegs =+  [VanillaReg i VGcPtr | i <- [1 .. 10]]+    <> [FloatReg i | i <- [1 .. 6]]+    <> [DoubleReg i | i <- [1 .. 6]]+    <> [LongReg i | i <- [1 .. 1]]+    <> [Sp, SpLim, Hp, HpLim, CCCS]++-- | Allocate a fresh symbol for an internal data section.+allocDataSection :: DataSection -> WasmCodeGenM w SymName+allocDataSection sec = do+  u <- wasmUniq+  let sym = fromString $ ".L" <> show u+  wasmModifyM $ \s ->+    s+      { dataSections =+          addToUniqMap (dataSections s) sym sec+      }+  pure sym++-- | Print a debug message to stderr by calling @fputs()@. We don't+-- bother to check @fputs()@ return value.+wasmDebugMsg :: String -> WasmCodeGenM w (WasmStatements w)+wasmDebugMsg msg = do+  ty_word_cmm <- wasmWordCmmTypeM+  sym_buf <-+    allocDataSection+      DataSection+        { dataSectionKind =+            SectionROData,+          dataSectionAlignment =+            mkAlignment 1,+          dataSectionContents =+            [DataASCII $ fromString $ msg <> "\NUL"]+        }+  onFuncSym "fputs" [ty_word_cmm, ty_word_cmm] [b32]+  pure $+    WasmStatements $+      WasmSymConst sym_buf+        `WasmConcat` WasmSymConst "__stderr_FILE"+        `WasmConcat` WasmCCall "fputs"+        `WasmConcat` WasmDrop++-- | Truncate a subword.+truncSubword :: Width -> WasmTypeTag t -> WasmExpr w t -> WasmExpr w t+truncSubword W8 ty (WasmExpr instr) =+  WasmExpr $ instr `WasmConcat` WasmConst ty 0xFF `WasmConcat` WasmAnd ty+truncSubword W16 ty (WasmExpr instr) =+  WasmExpr $ instr `WasmConcat` WasmConst ty 0xFFFF `WasmConcat` WasmAnd ty+truncSubword _ _ expr = expr++-- | Sign-extend a subword.+extendSubword :: Width -> WasmTypeTag t -> WasmExpr w t -> WasmExpr w t+extendSubword W8 TagI32 (WasmExpr instr) =+  WasmExpr $ instr `WasmConcat` WasmI32Extend8S+extendSubword W16 TagI32 (WasmExpr instr) =+  WasmExpr $ instr `WasmConcat` WasmI32Extend16S+extendSubword W8 TagI64 (WasmExpr instr) =+  WasmExpr $ instr `WasmConcat` WasmI64Extend8S+extendSubword W16 TagI64 (WasmExpr instr) =+  WasmExpr $ instr `WasmConcat` WasmI64Extend16S+extendSubword W32 TagI64 (WasmExpr instr) =+  WasmExpr $ instr `WasmConcat` WasmI64Extend32S+extendSubword _ _ expr = expr++-- | Lower a binary homogeneous operation. Homogeneous: result type is+-- the same with operand types.+lower_MO_Bin_Homo ::+  ( forall pre t.+    WasmTypeTag t ->+    WasmInstr+      w+      (t : t : pre)+      (t : pre)+  ) ->+  CLabel ->+  CmmType ->+  [CmmExpr] ->+  WasmCodeGenM w (SomeWasmExpr w)+lower_MO_Bin_Homo op lbl t0 [x, y] = case someWasmTypeFromCmmType t0 of+  SomeWasmType ty -> do+    WasmExpr x_instr <- lower_CmmExpr_Typed lbl ty x+    WasmExpr y_instr <- lower_CmmExpr_Typed lbl ty y+    pure $+      SomeWasmExpr ty $+        WasmExpr $+          x_instr `WasmConcat` y_instr `WasmConcat` op ty+lower_MO_Bin_Homo _ _ _ _ = panic "lower_MO_Bin_Homo: unreachable"++-- | Lower a binary homogeneous operation, and truncate the result if+-- it's a subword.+lower_MO_Bin_Homo_Trunc ::+  (forall pre t. WasmTypeTag t -> WasmInstr w (t : t : pre) (t : pre)) ->+  CLabel ->+  Width ->+  [CmmExpr] ->+  WasmCodeGenM w (SomeWasmExpr w)+lower_MO_Bin_Homo_Trunc op lbl w0 [x, y] =+  case someWasmTypeFromCmmType (cmmBits w0) of+    SomeWasmType ty -> do+      WasmExpr x_instr <- lower_CmmExpr_Typed lbl ty x+      WasmExpr y_instr <- lower_CmmExpr_Typed lbl ty y+      pure $+        SomeWasmExpr ty $+          truncSubword w0 ty $+            WasmExpr $+              x_instr `WasmConcat` y_instr `WasmConcat` op ty+lower_MO_Bin_Homo_Trunc _ _ _ _ = panic "lower_MO_Bin_Homo_Trunc: unreachable"++-- | Lower a binary homogeneous operation, first sign extending the+-- operands, then truncating the result.+lower_MO_Bin_Homo_Ext_Trunc ::+  (forall pre t. WasmTypeTag t -> WasmInstr w (t : t : pre) (t : pre)) ->+  CLabel ->+  Width ->+  [CmmExpr] ->+  WasmCodeGenM w (SomeWasmExpr w)+lower_MO_Bin_Homo_Ext_Trunc op lbl w0 [x, y] =+  case someWasmTypeFromCmmType (cmmBits w0) of+    SomeWasmType ty -> do+      WasmExpr x_instr <-+        extendSubword w0 ty <$> lower_CmmExpr_Typed lbl ty x+      WasmExpr y_instr <-+        extendSubword w0 ty <$> lower_CmmExpr_Typed lbl ty y+      pure $+        SomeWasmExpr ty $+          truncSubword w0 ty $+            WasmExpr $+              x_instr `WasmConcat` y_instr `WasmConcat` op ty+lower_MO_Bin_Homo_Ext_Trunc _ _ _ _ =+  panic "lower_MO_Bin_Homo_Ext_Trunc: unreachable"++-- | Lower a relational binary operation, first sign extending the+-- operands. Relational: result type is a boolean (word type).+lower_MO_Bin_Rel_Ext ::+  (forall pre t. WasmTypeTag t -> WasmInstr w (t : t : pre) (w : pre)) ->+  CLabel ->+  Width ->+  [CmmExpr] ->+  WasmCodeGenM w (SomeWasmExpr w)+lower_MO_Bin_Rel_Ext op lbl w0 [x, y] =+  case someWasmTypeFromCmmType (cmmBits w0) of+    SomeWasmType ty -> do+      WasmExpr x_instr <-+        extendSubword w0 ty <$> lower_CmmExpr_Typed lbl ty x+      WasmExpr y_instr <-+        extendSubword w0 ty <$> lower_CmmExpr_Typed lbl ty y+      ty_word <- wasmWordTypeM+      pure $+        SomeWasmExpr ty_word $+          WasmExpr $+            x_instr `WasmConcat` y_instr `WasmConcat` op ty+lower_MO_Bin_Rel_Ext _ _ _ _ = panic "lower_MO_Bin_Rel_Ext: unreachable"++-- | Lower a relational binary operation.+lower_MO_Bin_Rel ::+  ( forall pre t.+    WasmTypeTag t ->+    WasmInstr+      w+      (t : t : pre)+      (w : pre)+  ) ->+  CLabel ->+  CmmType ->+  [CmmExpr] ->+  WasmCodeGenM w (SomeWasmExpr w)+lower_MO_Bin_Rel op lbl t0 [x, y] = case someWasmTypeFromCmmType t0 of+  SomeWasmType ty -> do+    WasmExpr x_instr <- lower_CmmExpr_Typed lbl ty x+    WasmExpr y_instr <- lower_CmmExpr_Typed lbl ty y+    ty_word <- wasmWordTypeM+    pure $+      SomeWasmExpr ty_word $+        WasmExpr $+          x_instr `WasmConcat` y_instr `WasmConcat` op ty+lower_MO_Bin_Rel _ _ _ _ = panic "lower_MO_Bin_Rel: unreachable"++-- | Cast a shiftL/shiftR RHS to the same type as LHS. Because we may+-- have a 64-bit LHS and 32-bit RHS, but wasm shift operators are+-- homogeneous.+shiftRHSCast ::+  CLabel ->+  WasmTypeTag t ->+  CmmExpr ->+  WasmCodeGenM+    w+    (WasmExpr w t)+shiftRHSCast lbl t1 x = do+  SomeWasmExpr t0 (WasmExpr x_instr) <- lower_CmmExpr lbl x+  if+      | Just Refl <- t0 `testEquality` t1 -> pure $ WasmExpr x_instr+      | TagI32 <- t0,+        TagI64 <- t1 ->+          pure $ WasmExpr $ x_instr `WasmConcat` WasmI64ExtendI32 Unsigned+      | otherwise -> panic "shiftRHSCast: unreachable"++-- | Lower a 'MO_Shl' operation, truncating the result.+lower_MO_Shl ::+  CLabel ->+  Width ->+  [CmmExpr] ->+  WasmCodeGenM+    w+    (SomeWasmExpr w)+lower_MO_Shl lbl w0 [x, y] = case someWasmTypeFromCmmType (cmmBits w0) of+  SomeWasmType ty -> do+    WasmExpr x_instr <- lower_CmmExpr_Typed lbl ty x+    WasmExpr y_instr <- shiftRHSCast lbl ty y+    pure $+      SomeWasmExpr ty $+        truncSubword w0 ty $+          WasmExpr $+            x_instr `WasmConcat` y_instr `WasmConcat` WasmShl ty+lower_MO_Shl _ _ _ = panic "lower_MO_Shl: unreachable"++-- | Lower a 'MO_U_Shr' operation.+lower_MO_U_Shr ::+  CLabel ->+  Width ->+  [CmmExpr] ->+  WasmCodeGenM+    w+    (SomeWasmExpr w)+lower_MO_U_Shr lbl w0 [x, y] = case someWasmTypeFromCmmType (cmmBits w0) of+  SomeWasmType ty -> do+    WasmExpr x_instr <- lower_CmmExpr_Typed lbl ty x+    WasmExpr y_instr <- shiftRHSCast lbl ty y+    pure $+      SomeWasmExpr ty $+        WasmExpr $+          x_instr `WasmConcat` y_instr `WasmConcat` WasmShr Unsigned ty+lower_MO_U_Shr _ _ _ = panic "lower_MO_U_Shr: unreachable"++-- | Lower a 'MO_S_Shr' operation, first sign-extending the LHS, then+-- truncating the result.+lower_MO_S_Shr ::+  CLabel ->+  Width ->+  [CmmExpr] ->+  WasmCodeGenM+    w+    (SomeWasmExpr w)+lower_MO_S_Shr lbl w0 [x, y] = case someWasmTypeFromCmmType (cmmBits w0) of+  SomeWasmType ty -> do+    WasmExpr x_instr <- extendSubword w0 ty <$> lower_CmmExpr_Typed lbl ty x+    WasmExpr y_instr <- shiftRHSCast lbl ty y+    pure $+      SomeWasmExpr ty $+        truncSubword w0 ty $+          WasmExpr $+            x_instr `WasmConcat` y_instr `WasmConcat` WasmShr Signed ty+lower_MO_S_Shr _ _ _ = panic "lower_MO_S_Shr: unreachable"++-- | Lower a 'MO_MulMayOflo' operation. It's translated to a ccall to+-- @hs_mulIntMayOflo@ function in @ghc-prim/cbits/mulIntMayOflo@,+-- otherwise it's quite non-trivial to implement as inline assembly.+lower_MO_MulMayOflo ::+  CLabel -> Width -> [CmmExpr] -> WasmCodeGenM w (SomeWasmExpr w)+lower_MO_MulMayOflo lbl w0 [x, y] = case someWasmTypeFromCmmType ty_cmm of+  SomeWasmType ty -> do+    WasmExpr x_instr <- lower_CmmExpr_Typed lbl ty x+    WasmExpr y_instr <- lower_CmmExpr_Typed lbl ty y+    onFuncSym "hs_mulIntMayOflo" [ty_cmm, ty_cmm] [ty_cmm]+    pure $+      SomeWasmExpr ty $+        WasmExpr $+          x_instr+            `WasmConcat` y_instr+            `WasmConcat` WasmCCall "hs_mulIntMayOflo"+  where+    ty_cmm = cmmBits w0+lower_MO_MulMayOflo _ _ _ = panic "lower_MO_MulMayOflo: unreachable"++-- | Lower an unary conversion operation.+lower_MO_Un_Conv ::+  ( forall pre t0 t1.+    WasmTypeTag t0 ->+    WasmTypeTag t1 ->+    WasmInstr w (t0 : pre) (t1 : pre)+  ) ->+  CLabel ->+  CmmType ->+  CmmType ->+  [CmmExpr] ->+  WasmCodeGenM w (SomeWasmExpr w)+lower_MO_Un_Conv op lbl t0 t1 [x] =+  case (# someWasmTypeFromCmmType t0, someWasmTypeFromCmmType t1 #) of+    (# SomeWasmType ty0, SomeWasmType ty1 #) -> do+      WasmExpr x_instr <- lower_CmmExpr_Typed lbl ty0 x+      pure $ SomeWasmExpr ty1 $ WasmExpr $ x_instr `WasmConcat` op ty0 ty1+lower_MO_Un_Conv _ _ _ _ _ = panic "lower_MO_Un_Conv: unreachable"++-- | Lower a 'MO_SS_Conv' operation.+lower_MO_SS_Conv ::+  CLabel ->+  Width ->+  Width ->+  [CmmExpr] ->+  WasmCodeGenM+    w+    (SomeWasmExpr w)+lower_MO_SS_Conv lbl w0 w1 [x]+  | w0 == w1 = lower_CmmExpr lbl x+lower_MO_SS_Conv lbl w0 w1 [CmmLoad ptr _ align]+  | w0 < w1,+    w1 <= W32 = do+      (WasmExpr ptr_instr, o) <- lower_CmmExpr_Ptr lbl ptr+      pure $+        SomeWasmExpr TagI32 $+          truncSubword w1 TagI32 $+            WasmExpr $+              ptr_instr+                `WasmConcat` WasmLoad+                  TagI32+                  (wasmMemoryNarrowing TagI32 (cmmBits w0))+                  Signed+                  o+                  align+  | w0 > w1 =+      SomeWasmExpr TagI32+        <$> lower_CmmLoad_Typed+          lbl+          ptr+          TagI32+          (cmmBits w1)+          align+lower_MO_SS_Conv lbl w0 W64 [CmmLoad ptr _ align] = do+  (WasmExpr ptr_instr, o) <- lower_CmmExpr_Ptr lbl ptr+  pure $+    SomeWasmExpr TagI64 $+      WasmExpr $+        ptr_instr+          `WasmConcat` WasmLoad+            TagI64+            (wasmMemoryNarrowing TagI64 (cmmBits w0))+            Signed+            o+            align+lower_MO_SS_Conv lbl w0 w1 [x]+  | w0 < w1,+    w1 <= W32 = do+      x_expr <- lower_CmmExpr_Typed lbl TagI32 x+      pure $+        SomeWasmExpr TagI32 $+          truncSubword w1 TagI32 $+            extendSubword w0 TagI32 x_expr+  | W32 >= w0,+    w0 > w1 = do+      x_expr <- lower_CmmExpr_Typed lbl TagI32 x+      pure $ SomeWasmExpr TagI32 $ truncSubword w1 TagI32 x_expr+lower_MO_SS_Conv lbl W32 W64 [x] = do+  WasmExpr x_instr <- lower_CmmExpr_Typed lbl TagI32 x+  pure $+    SomeWasmExpr TagI64 $+      WasmExpr $+        x_instr `WasmConcat` WasmI64ExtendI32 Signed+lower_MO_SS_Conv lbl w0 W64 [x] = do+  WasmExpr x_instr <- lower_CmmExpr_Typed lbl TagI32 x+  pure $+    SomeWasmExpr TagI64 $+      extendSubword w0 TagI64 $+        WasmExpr $+          x_instr `WasmConcat` WasmI64ExtendI32 Unsigned+lower_MO_SS_Conv lbl W64 w1 [x] = do+  WasmExpr x_instr <- lower_CmmExpr_Typed lbl TagI64 x+  pure $+    SomeWasmExpr TagI32 $+      truncSubword w1 TagI32 $+        WasmExpr $+          x_instr `WasmConcat` WasmI32WrapI64+lower_MO_SS_Conv _ _ _ _ = panic "lower_MO_SS_Conv: unreachable"++-- | Lower a 'MO_UU_Conv' operation.+lower_MO_UU_Conv ::+  CLabel ->+  Width ->+  Width ->+  [CmmExpr] ->+  WasmCodeGenM+    w+    (SomeWasmExpr w)+lower_MO_UU_Conv lbl w0 w1 [CmmLoad ptr _ align] =+  case someWasmTypeFromCmmType (cmmBits w1) of+    SomeWasmType ty ->+      SomeWasmExpr ty+        <$> lower_CmmLoad_Typed+          lbl+          ptr+          ty+          (cmmBits (min w0 w1))+          align+lower_MO_UU_Conv lbl w0 w1 [x]+  | w0 == w1 = lower_CmmExpr lbl x+  | w0 < w1, w1 <= W32 = lower_CmmExpr lbl x+  | W32 >= w0,+    w0 > w1 = do+      x_expr <- lower_CmmExpr_Typed lbl TagI32 x+      pure $ SomeWasmExpr TagI32 $ truncSubword w1 TagI32 x_expr+lower_MO_UU_Conv lbl _ W64 [x] = do+  WasmExpr x_instr <- lower_CmmExpr_Typed lbl TagI32 x+  pure $+    SomeWasmExpr TagI64 $+      WasmExpr $+        x_instr `WasmConcat` WasmI64ExtendI32 Unsigned+lower_MO_UU_Conv lbl W64 w1 [x] = do+  WasmExpr x_instr <- lower_CmmExpr_Typed lbl TagI64 x+  pure $+    SomeWasmExpr TagI32 $+      truncSubword w1 TagI32 $+        WasmExpr $+          x_instr `WasmConcat` WasmI32WrapI64+lower_MO_UU_Conv _ _ _ _ = panic "lower_MO_UU_Conv: unreachable"++-- | Lower a 'MO_FF_Conv' operation.+lower_MO_FF_Conv ::+  CLabel ->+  Width ->+  Width ->+  [CmmExpr] ->+  WasmCodeGenM+    w+    (SomeWasmExpr w)+lower_MO_FF_Conv lbl W32 W64 [x] = do+  WasmExpr x_instr <- lower_CmmExpr_Typed lbl TagF32 x+  pure $+    SomeWasmExpr TagF64 $+      WasmExpr $+        x_instr `WasmConcat` WasmF64PromoteF32+lower_MO_FF_Conv lbl W64 W32 [x] = do+  WasmExpr x_instr <- lower_CmmExpr_Typed lbl TagF64 x+  pure $+    SomeWasmExpr TagF32 $+      WasmExpr $+        x_instr `WasmConcat` WasmF32DemoteF64+lower_MO_FF_Conv _ _ _ _ = panic "lower_MO_FF_Conv: unreachable"++-- | Lower a 'CmmMachOp'.+lower_CmmMachOp ::+  CLabel ->+  MachOp ->+  [CmmExpr] ->+  WasmCodeGenM+    w+    (SomeWasmExpr w)+lower_CmmMachOp lbl (MO_Add w0) xs = lower_MO_Bin_Homo_Trunc WasmAdd lbl w0 xs+lower_CmmMachOp lbl (MO_Sub w0) xs = lower_MO_Bin_Homo_Trunc WasmSub lbl w0 xs+lower_CmmMachOp lbl (MO_Eq w0) xs = lower_MO_Bin_Rel WasmEq lbl (cmmBits w0) xs+lower_CmmMachOp lbl (MO_Ne w0) xs = lower_MO_Bin_Rel WasmNe lbl (cmmBits w0) xs+lower_CmmMachOp lbl (MO_Mul w0) xs = lower_MO_Bin_Homo_Trunc WasmMul lbl w0 xs+lower_CmmMachOp lbl (MO_S_MulMayOflo w0) xs = lower_MO_MulMayOflo lbl w0 xs+lower_CmmMachOp lbl (MO_S_Quot w0) xs =+  lower_MO_Bin_Homo_Ext_Trunc+    (WasmDiv Signed)+    lbl+    w0+    xs+lower_CmmMachOp lbl (MO_S_Rem w0) xs =+  lower_MO_Bin_Homo_Ext_Trunc+    (WasmRem Signed)+    lbl+    w0+    xs+lower_CmmMachOp lbl (MO_S_Neg w0) [x] =+  lower_CmmMachOp+    lbl+    (MO_Sub w0)+    [CmmLit $ CmmInt 0 w0, x]+lower_CmmMachOp lbl (MO_U_Quot w0) xs =+  lower_MO_Bin_Homo+    (WasmDiv Unsigned)+    lbl+    (cmmBits w0)+    xs+lower_CmmMachOp lbl (MO_U_Rem w0) xs =+  lower_MO_Bin_Homo+    (WasmRem Unsigned)+    lbl+    (cmmBits w0)+    xs+lower_CmmMachOp lbl (MO_S_Ge w0) xs =+  lower_MO_Bin_Rel_Ext+    (WasmGe Signed)+    lbl+    w0+    xs+lower_CmmMachOp lbl (MO_S_Le w0) xs =+  lower_MO_Bin_Rel_Ext+    (WasmLe Signed)+    lbl+    w0+    xs+lower_CmmMachOp lbl (MO_S_Gt w0) xs =+  lower_MO_Bin_Rel_Ext+    (WasmGt Signed)+    lbl+    w0+    xs+lower_CmmMachOp lbl (MO_S_Lt w0) xs =+  lower_MO_Bin_Rel_Ext+    (WasmLt Signed)+    lbl+    w0+    xs+lower_CmmMachOp lbl (MO_U_Ge w0) xs =+  lower_MO_Bin_Rel+    (WasmGe Unsigned)+    lbl+    (cmmBits w0)+    xs+lower_CmmMachOp lbl (MO_U_Le w0) xs =+  lower_MO_Bin_Rel+    (WasmLe Unsigned)+    lbl+    (cmmBits w0)+    xs+lower_CmmMachOp lbl (MO_U_Gt w0) xs =+  lower_MO_Bin_Rel+    (WasmGt Unsigned)+    lbl+    (cmmBits w0)+    xs+lower_CmmMachOp lbl (MO_U_Lt w0) xs =+  lower_MO_Bin_Rel+    (WasmLt Unsigned)+    lbl+    (cmmBits w0)+    xs+lower_CmmMachOp lbl (MO_F_Add w0) xs =+  lower_MO_Bin_Homo+    WasmAdd+    lbl+    (cmmFloat w0)+    xs+lower_CmmMachOp lbl (MO_F_Sub w0) xs =+  lower_MO_Bin_Homo+    WasmSub+    lbl+    (cmmFloat w0)+    xs+lower_CmmMachOp lbl (MO_F_Neg w0) [x] =+  lower_CmmMachOp+    lbl+    (MO_F_Sub w0)+    [CmmLit $ CmmFloat 0 w0, x]+lower_CmmMachOp lbl (MO_F_Mul w0) xs =+  lower_MO_Bin_Homo+    WasmMul+    lbl+    (cmmFloat w0)+    xs+lower_CmmMachOp lbl (MO_F_Quot w0) xs =+  lower_MO_Bin_Homo+    (WasmDiv Signed)+    lbl+    (cmmFloat w0)+    xs+lower_CmmMachOp lbl (MO_F_Eq w0) xs =+  lower_MO_Bin_Rel+    WasmEq+    lbl+    (cmmFloat w0)+    xs+lower_CmmMachOp lbl (MO_F_Ne w0) xs =+  lower_MO_Bin_Rel+    WasmNe+    lbl+    (cmmFloat w0)+    xs+lower_CmmMachOp lbl (MO_F_Ge w0) xs =+  lower_MO_Bin_Rel+    (WasmGe Signed)+    lbl+    (cmmFloat w0)+    xs+lower_CmmMachOp lbl (MO_F_Le w0) xs =+  lower_MO_Bin_Rel+    (WasmLe Signed)+    lbl+    (cmmFloat w0)+    xs+lower_CmmMachOp lbl (MO_F_Gt w0) xs =+  lower_MO_Bin_Rel+    (WasmGt Signed)+    lbl+    (cmmFloat w0)+    xs+lower_CmmMachOp lbl (MO_F_Lt w0) xs =+  lower_MO_Bin_Rel+    (WasmLt Signed)+    lbl+    (cmmFloat w0)+    xs+lower_CmmMachOp lbl (MO_And w0) xs =+  lower_MO_Bin_Homo+    WasmAnd+    lbl+    (cmmBits w0)+    xs+lower_CmmMachOp lbl (MO_Or w0) xs = lower_MO_Bin_Homo WasmOr lbl (cmmBits w0) xs+lower_CmmMachOp lbl (MO_Xor w0) xs =+  lower_MO_Bin_Homo+    WasmXor+    lbl+    (cmmBits w0)+    xs+lower_CmmMachOp lbl (MO_Not w0) [x] =+  lower_CmmMachOp+    lbl+    (MO_Xor w0)+    [x, CmmLit $ CmmInt (widthMax w0) w0]+lower_CmmMachOp lbl (MO_Shl w0) xs = lower_MO_Shl lbl w0 xs+lower_CmmMachOp lbl (MO_U_Shr w0) xs = lower_MO_U_Shr lbl w0 xs+lower_CmmMachOp lbl (MO_S_Shr w0) xs = lower_MO_S_Shr lbl w0 xs+lower_CmmMachOp lbl (MO_SF_Conv w0 w1) xs =+  lower_MO_Un_Conv+    (WasmConvert Signed)+    lbl+    (cmmBits w0)+    (cmmFloat w1)+    xs+lower_CmmMachOp lbl (MO_FS_Conv w0 w1) xs =+  lower_MO_Un_Conv+    (WasmTruncSat Signed)+    lbl+    (cmmFloat w0)+    (cmmBits w1)+    xs+lower_CmmMachOp lbl (MO_SS_Conv w0 w1) xs = lower_MO_SS_Conv lbl w0 w1 xs+lower_CmmMachOp lbl (MO_UU_Conv w0 w1) xs = lower_MO_UU_Conv lbl w0 w1 xs+lower_CmmMachOp lbl (MO_XX_Conv w0 w1) xs = lower_MO_UU_Conv lbl w0 w1 xs+lower_CmmMachOp lbl (MO_FF_Conv w0 w1) xs = lower_MO_FF_Conv lbl w0 w1 xs+lower_CmmMachOp _ _ _ = panic "lower_CmmMachOp: unreachable"++-- | Lower a 'CmmLit'. Note that we don't emit 'f32.const' or+-- 'f64.const' for the time being, and instead emit their relative bit+-- pattern as int literals, then use an reinterpret cast. This is+-- simpler than dealing with textual representation of floating point+-- values.+lower_CmmLit :: CmmLit -> WasmCodeGenM w (SomeWasmExpr w)+lower_CmmLit lit = do+  ty_word <- wasmWordTypeM+  case lit of+    CmmInt i w -> case someWasmTypeFromCmmType (cmmBits w) of+      SomeWasmType ty ->+        pure $+          SomeWasmExpr ty $+            WasmExpr $+              WasmConst ty $+                naturalNarrowing w i+    CmmFloat f W32 ->+      pure $+        SomeWasmExpr TagF32 $+          WasmExpr $+            WasmConst+              TagI32+              (toInteger $ castFloatToWord32 $ fromRational f)+              `WasmConcat` WasmReinterpret TagI32 TagF32+    CmmFloat f W64 ->+      pure $+        SomeWasmExpr TagF64 $+          WasmExpr $+            WasmConst+              TagI64+              (toInteger $ castDoubleToWord64 $ fromRational f)+              `WasmConcat` WasmReinterpret TagI64 TagF64+    CmmLabel lbl' -> do+      onAnySym lbl'+      let sym = symNameFromCLabel lbl'+      pure $ SomeWasmExpr ty_word $ WasmExpr $ WasmSymConst sym+    CmmLabelOff lbl' o -> do+      onAnySym lbl'+      let sym = symNameFromCLabel lbl'+      pure $+        SomeWasmExpr ty_word $+          WasmExpr $+            WasmSymConst sym+              `WasmConcat` WasmConst ty_word (toInteger o)+              `WasmConcat` WasmAdd ty_word+    _ -> panic "lower_CmmLit: unreachable"++--  | Lower a 'CmmReg'. Some of the logic here wouldn't be needed if+--  we have run 'fixStgRegisters' on the wasm NCG's input Cmm, but we+--  haven't run it yet for certain reasons.+lower_CmmReg :: CLabel -> CmmReg -> WasmCodeGenM w (SomeWasmExpr w)+lower_CmmReg _ (CmmLocal reg) = do+  (reg_i, SomeWasmType ty) <- onCmmLocalReg reg+  pure $ SomeWasmExpr ty $ WasmExpr $ WasmLocalGet ty reg_i+lower_CmmReg _ (CmmGlobal EagerBlackholeInfo) = do+  ty_word <- wasmWordTypeM+  pure $+    SomeWasmExpr ty_word $+      WasmExpr $+        WasmSymConst "stg_EAGER_BLACKHOLE_info"+lower_CmmReg _ (CmmGlobal GCEnter1) = do+  ty_word <- wasmWordTypeM+  ty_word_cmm <- wasmWordCmmTypeM+  onFuncSym "__stg_gc_enter_1" [] [ty_word_cmm]+  pure $ SomeWasmExpr ty_word $ WasmExpr $ WasmSymConst "__stg_gc_enter_1"+lower_CmmReg _ (CmmGlobal GCFun) = do+  ty_word <- wasmWordTypeM+  ty_word_cmm <- wasmWordCmmTypeM+  onFuncSym "__stg_gc_fun" [] [ty_word_cmm]+  pure $ SomeWasmExpr ty_word $ WasmExpr $ WasmSymConst "__stg_gc_fun"+lower_CmmReg lbl (CmmGlobal BaseReg) = do+  platform <- wasmPlatformM+  lower_CmmExpr lbl $ regTableOffset platform 0+lower_CmmReg lbl (CmmGlobal reg) = do+  ty_word <- wasmWordTypeM+  if+      | Just (sym_global, SomeWasmType ty) <-+          globalInfoFromCmmGlobalReg ty_word reg ->+          pure $ SomeWasmExpr ty $ WasmExpr $ WasmGlobalGet ty sym_global+      | otherwise -> do+          platform <- wasmPlatformM+          case someWasmTypeFromCmmType $ globalRegType platform reg of+            SomeWasmType ty -> do+              (WasmExpr ptr_instr, o) <-+                lower_CmmExpr_Ptr lbl $+                  get_GlobalReg_addr platform reg+              pure $+                SomeWasmExpr ty $+                  WasmExpr $+                    ptr_instr+                      `WasmConcat` WasmLoad+                        ty+                        Nothing+                        Unsigned+                        o+                        NaturallyAligned++-- | Lower a 'CmmRegOff'.+lower_CmmRegOff :: CLabel -> CmmReg -> Int -> WasmCodeGenM w (SomeWasmExpr w)+lower_CmmRegOff lbl reg 0 = lower_CmmReg lbl reg+lower_CmmRegOff lbl reg o = do+  SomeWasmExpr ty (WasmExpr reg_instr) <- lower_CmmReg lbl reg+  pure $+    SomeWasmExpr ty $+      WasmExpr $+        reg_instr+          `WasmConcat` WasmConst+            ty+            (toInteger o)+          `WasmConcat` WasmAdd ty++-- | Lower a 'CmmLoad', passing in the expected wasm representation+-- type, and also the Cmm type (which contains width info needed for+-- memory narrowing).+--+-- The Cmm type system doesn't track signedness, so all 'CmmLoad's are+-- unsigned loads. However, as an optimization, we do emit signed+-- loads when a 'CmmLoad' result is immediately used as a 'MO_SS_Conv'+-- operand.+lower_CmmLoad_Typed ::+  CLabel ->+  CmmExpr ->+  WasmTypeTag t ->+  CmmType ->+  AlignmentSpec ->+  WasmCodeGenM w (WasmExpr w t)+lower_CmmLoad_Typed lbl ptr_expr ty ty_cmm align = do+  (WasmExpr ptr_instr, o) <- lower_CmmExpr_Ptr lbl ptr_expr+  pure $+    WasmExpr $+      ptr_instr+        `WasmConcat` WasmLoad+          ty+          (wasmMemoryNarrowing ty ty_cmm)+          Unsigned+          o+          align++-- | Lower a 'CmmLoad'.+lower_CmmLoad ::+  CLabel ->+  CmmExpr ->+  CmmType ->+  AlignmentSpec ->+  WasmCodeGenM+    w+    (SomeWasmExpr w)+lower_CmmLoad lbl ptr_expr ty_cmm align = case someWasmTypeFromCmmType ty_cmm of+  SomeWasmType ty ->+    SomeWasmExpr ty <$> lower_CmmLoad_Typed lbl ptr_expr ty ty_cmm align++-- | Lower a 'CmmExpr'.+lower_CmmExpr :: CLabel -> CmmExpr -> WasmCodeGenM w (SomeWasmExpr w)+lower_CmmExpr lbl expr = case expr of+  CmmLit lit -> lower_CmmLit lit+  CmmLoad ptr_expr ty_cmm align -> lower_CmmLoad lbl ptr_expr ty_cmm align+  CmmReg reg -> lower_CmmReg lbl reg+  CmmRegOff reg o -> lower_CmmRegOff lbl reg o+  CmmMachOp op xs -> lower_CmmMachOp lbl op xs+  _ -> panic "lower_CmmExpr: unreachable"++-- | Lower a 'CmmExpr', passing in the expected wasm representation+-- type.+lower_CmmExpr_Typed ::+  CLabel ->+  WasmTypeTag t ->+  CmmExpr ->+  WasmCodeGenM+    w+    (WasmExpr w t)+lower_CmmExpr_Typed lbl ty expr = do+  SomeWasmExpr ty' r <- lower_CmmExpr lbl expr+  if+      | Just Refl <- ty' `testEquality` ty -> pure r+      | otherwise -> panic "lower_CmmExpr_Typed: unreachable"++-- | Lower a 'CmmExpr' as a pointer, returning the pair of base+-- pointer and non-negative offset.+lower_CmmExpr_Ptr :: CLabel -> CmmExpr -> WasmCodeGenM w (WasmExpr w w, Int)+lower_CmmExpr_Ptr lbl ptr = do+  ty_word <- wasmWordTypeM+  case ptr of+    CmmLit (CmmLabelOff lbl o)+      | o >= 0 -> do+          instrs <-+            lower_CmmExpr_Typed+              lbl+              ty_word+              (CmmLit $ CmmLabel lbl)+          pure (instrs, o)+    CmmMachOp (MO_Add _) [base, CmmLit (CmmInt o _)]+      | o >= 0 -> do+          instrs <- lower_CmmExpr_Typed lbl ty_word base+          pure (instrs, fromInteger o)+    _ -> do+      instrs <- lower_CmmExpr_Typed lbl ty_word ptr+      pure (instrs, 0)++-- | Push a series of values onto the wasm value stack, returning the+-- result stack type.+type family+  WasmPushes (ts :: [WasmType]) (pre :: [WasmType]) ::+    [WasmType]+  where+  WasmPushes '[] pre = pre+  WasmPushes (t : ts) pre = WasmPushes ts (t : pre)++-- | Push the arguments onto the wasm value stack before a ccall.+data SomeWasmPreCCall w where+  SomeWasmPreCCall ::+    TypeList ts ->+    (forall pre. WasmInstr w pre (WasmPushes ts pre)) ->+    SomeWasmPreCCall w++-- | Pop the results into locals after a ccall.+data SomeWasmPostCCall w where+  SomeWasmPostCCall ::+    TypeList ts ->+    (forall post. WasmInstr w (WasmPushes ts post) post) ->+    SomeWasmPostCCall w++-- | Lower an unary homogeneous 'CallishMachOp' to a ccall.+lower_CMO_Un_Homo ::+  CLabel ->+  SymName ->+  [CmmFormal] ->+  [CmmActual] ->+  WasmCodeGenM w (WasmStatements w)+lower_CMO_Un_Homo lbl op [reg] [x] = do+  (ri, SomeWasmType ty) <- onCmmLocalReg reg+  WasmExpr x_instr <- lower_CmmExpr_Typed lbl ty x+  let ty_cmm = localRegType reg+  onFuncSym op [ty_cmm] [ty_cmm]+  pure $+    WasmStatements $+      x_instr `WasmConcat` WasmCCall op `WasmConcat` WasmLocalSet ty ri+lower_CMO_Un_Homo _ _ _ _ = panic "lower_CMO_Un_Homo: unreachable"++-- | Lower an unary homogeneous 'CallishMachOp' to inline assembly.+lower_CMO_Un_Prim ::+  CLabel ->+  (forall pre t. WasmTypeTag t -> WasmInstr w (t : pre) (t : pre)) ->+  [CmmFormal] ->+  [CmmActual] ->+  WasmCodeGenM w (WasmStatements w)+lower_CMO_Un_Prim lbl op [reg] [x] = do+  (ri, SomeWasmType ty) <- onCmmLocalReg reg+  SomeWasmExpr ty_x (WasmExpr x_instr) <- lower_CmmExpr lbl x+  if+      | Just Refl <- ty `testEquality` ty_x ->+          pure $+            WasmStatements $+              x_instr `WasmConcat` op ty_x `WasmConcat` WasmLocalSet ty ri+      | TagI32 <- ty,+        TagI64 <-+          ty_x ->+          pure $+            WasmStatements $+              x_instr+                `WasmConcat` op ty_x+                `WasmConcat` WasmI32WrapI64+                `WasmConcat` WasmLocalSet ty ri+      | otherwise -> panic "lower_CMO_Un_Prim: unreachable"+lower_CMO_Un_Prim _ _ _ _ = panic "lower_CMO_Un_Prim: unreachable"++-- | Lower a binary homogeneous 'CallishMachOp' to a ccall.+lower_CMO_Bin_Homo ::+  CLabel ->+  SymName ->+  [CmmFormal] ->+  [CmmActual] ->+  WasmCodeGenM w (WasmStatements w)+lower_CMO_Bin_Homo lbl op [reg] [x, y] = do+  (ri, SomeWasmType ty) <- onCmmLocalReg reg+  WasmExpr x_instr <- lower_CmmExpr_Typed lbl ty x+  WasmExpr y_instr <- lower_CmmExpr_Typed lbl ty y+  let ty_cmm = localRegType reg+  onFuncSym op [ty_cmm, ty_cmm] [ty_cmm]+  pure $+    WasmStatements $+      x_instr+        `WasmConcat` y_instr+        `WasmConcat` WasmCCall op+        `WasmConcat` WasmLocalSet ty ri+lower_CMO_Bin_Homo _ _ _ _ = panic "lower_CMO_Bin_Homo: unreachable"++-- | Lower a 'MO_UF_Conv' operation.+lower_MO_UF_Conv ::+  CLabel ->+  Width ->+  [CmmFormal] ->+  [CmmActual] ->+  WasmCodeGenM w (WasmStatements w)+lower_MO_UF_Conv lbl W32 [reg] [x] = do+  ri <- onCmmLocalReg_Typed TagF32 reg+  SomeWasmExpr ty0 (WasmExpr x_instr) <- lower_CmmExpr lbl x+  pure $+    WasmStatements $+      x_instr+        `WasmConcat` WasmConvert Unsigned ty0 TagF32+        `WasmConcat` WasmLocalSet TagF32 ri+lower_MO_UF_Conv lbl W64 [reg] [x] = do+  ri <- onCmmLocalReg_Typed TagF64 reg+  SomeWasmExpr ty0 (WasmExpr x_instr) <- lower_CmmExpr lbl x+  pure $+    WasmStatements $+      x_instr+        `WasmConcat` WasmConvert Unsigned ty0 TagF64+        `WasmConcat` WasmLocalSet TagF64 ri+lower_MO_UF_Conv _ _ _ _ = panic "lower_MO_UF_Conv: unreachable"++-- | Lower a 'MO_Cmpxchg' operation to inline assembly. Currently we+-- target wasm without atomics and threads, so it's just lowered to+-- regular memory loads and stores.+lower_MO_Cmpxchg ::+  CLabel ->+  Width ->+  [CmmFormal] ->+  [CmmActual] ->+  WasmCodeGenM w (WasmStatements w)+lower_MO_Cmpxchg lbl w0 [reg] [ptr, expected, new] =+  case someWasmTypeFromCmmType ty_cmm of+    SomeWasmType ty -> do+      reg_i <- onCmmLocalReg_Typed ty reg+      let narrowing = wasmMemoryNarrowing ty ty_cmm+      (WasmExpr ptr_instr, o) <- lower_CmmExpr_Ptr lbl ptr+      WasmExpr expected_instr <- lower_CmmExpr_Typed lbl ty expected+      WasmExpr new_instr <- lower_CmmExpr_Typed lbl ty new+      pure $+        WasmStatements $+          ptr_instr+            `WasmConcat` WasmLoad ty narrowing Unsigned o NaturallyAligned+            `WasmConcat` WasmLocalTee ty reg_i+            `WasmConcat` expected_instr+            `WasmConcat` WasmEq ty+            `WasmConcat` WasmCond+              ( ptr_instr+                  `WasmConcat` new_instr+                  `WasmConcat` WasmStore ty narrowing o NaturallyAligned+              )+  where+    ty_cmm = cmmBits w0+lower_MO_Cmpxchg _ _ _ _ = panic "lower_MO_Cmpxchg: unreachable"++-- | Lower a 'CallishMachOp'.+lower_CallishMachOp ::+  CLabel ->+  CallishMachOp ->+  [CmmFormal] ->+  [CmmActual] ->+  WasmCodeGenM w (WasmStatements w)+lower_CallishMachOp lbl MO_F64_Pwr rs xs = lower_CMO_Bin_Homo lbl "pow" rs xs+lower_CallishMachOp lbl MO_F64_Sin rs xs = lower_CMO_Un_Homo lbl "sin" rs xs+lower_CallishMachOp lbl MO_F64_Cos rs xs = lower_CMO_Un_Homo lbl "cos" rs xs+lower_CallishMachOp lbl MO_F64_Tan rs xs = lower_CMO_Un_Homo lbl "tan" rs xs+lower_CallishMachOp lbl MO_F64_Sinh rs xs = lower_CMO_Un_Homo lbl "sinh" rs xs+lower_CallishMachOp lbl MO_F64_Cosh rs xs = lower_CMO_Un_Homo lbl "cosh" rs xs+lower_CallishMachOp lbl MO_F64_Tanh rs xs = lower_CMO_Un_Homo lbl "tanh" rs xs+lower_CallishMachOp lbl MO_F64_Asin rs xs = lower_CMO_Un_Homo lbl "asin" rs xs+lower_CallishMachOp lbl MO_F64_Acos rs xs = lower_CMO_Un_Homo lbl "acos" rs xs+lower_CallishMachOp lbl MO_F64_Atan rs xs = lower_CMO_Un_Homo lbl "atan" rs xs+lower_CallishMachOp lbl MO_F64_Asinh rs xs = lower_CMO_Un_Homo lbl "asinh" rs xs+lower_CallishMachOp lbl MO_F64_Acosh rs xs = lower_CMO_Un_Homo lbl "acosh" rs xs+lower_CallishMachOp lbl MO_F64_Atanh rs xs = lower_CMO_Un_Homo lbl "atanh" rs xs+lower_CallishMachOp lbl MO_F64_Log rs xs = lower_CMO_Un_Homo lbl "log" rs xs+lower_CallishMachOp lbl MO_F64_Log1P rs xs = lower_CMO_Un_Homo lbl "log1p" rs xs+lower_CallishMachOp lbl MO_F64_Exp rs xs = lower_CMO_Un_Homo lbl "exp" rs xs+lower_CallishMachOp lbl MO_F64_ExpM1 rs xs = lower_CMO_Un_Homo lbl "expm1" rs xs+lower_CallishMachOp lbl MO_F64_Fabs rs xs = lower_CMO_Un_Homo lbl "fabs" rs xs+lower_CallishMachOp lbl MO_F64_Sqrt rs xs = lower_CMO_Un_Homo lbl "sqrt" rs xs+lower_CallishMachOp lbl MO_F32_Pwr rs xs = lower_CMO_Bin_Homo lbl "powf" rs xs+lower_CallishMachOp lbl MO_F32_Sin rs xs = lower_CMO_Un_Homo lbl "sinf" rs xs+lower_CallishMachOp lbl MO_F32_Cos rs xs = lower_CMO_Un_Homo lbl "cosf" rs xs+lower_CallishMachOp lbl MO_F32_Tan rs xs = lower_CMO_Un_Homo lbl "tanf" rs xs+lower_CallishMachOp lbl MO_F32_Sinh rs xs = lower_CMO_Un_Homo lbl "sinhf" rs xs+lower_CallishMachOp lbl MO_F32_Cosh rs xs = lower_CMO_Un_Homo lbl "coshf" rs xs+lower_CallishMachOp lbl MO_F32_Tanh rs xs = lower_CMO_Un_Homo lbl "tanhf" rs xs+lower_CallishMachOp lbl MO_F32_Asin rs xs = lower_CMO_Un_Homo lbl "asinf" rs xs+lower_CallishMachOp lbl MO_F32_Acos rs xs = lower_CMO_Un_Homo lbl "acosf" rs xs+lower_CallishMachOp lbl MO_F32_Atan rs xs = lower_CMO_Un_Homo lbl "atanf" rs xs+lower_CallishMachOp lbl MO_F32_Asinh rs xs =+  lower_CMO_Un_Homo lbl "asinhf" rs xs+lower_CallishMachOp lbl MO_F32_Acosh rs xs =+  lower_CMO_Un_Homo lbl "acoshf" rs xs+lower_CallishMachOp lbl MO_F32_Atanh rs xs =+  lower_CMO_Un_Homo lbl "atanhf" rs xs+lower_CallishMachOp lbl MO_F32_Log rs xs = lower_CMO_Un_Homo lbl "logf" rs xs+lower_CallishMachOp lbl MO_F32_Log1P rs xs =+  lower_CMO_Un_Homo lbl "log1pf" rs xs+lower_CallishMachOp lbl MO_F32_Exp rs xs = lower_CMO_Un_Homo lbl "expf" rs xs+lower_CallishMachOp lbl MO_F32_ExpM1 rs xs =+  lower_CMO_Un_Homo lbl "expm1f" rs xs+lower_CallishMachOp lbl MO_F32_Fabs rs xs = lower_CMO_Un_Homo lbl "fabsf" rs xs+lower_CallishMachOp lbl MO_F32_Sqrt rs xs = lower_CMO_Un_Homo lbl "sqrtf" rs xs+lower_CallishMachOp lbl (MO_UF_Conv w0) rs xs = lower_MO_UF_Conv lbl w0 rs xs+lower_CallishMachOp _ MO_ReadBarrier _ _ = pure $ WasmStatements WasmNop+lower_CallishMachOp _ MO_WriteBarrier _ _ = pure $ WasmStatements WasmNop+lower_CallishMachOp _ MO_Touch _ _ = pure $ WasmStatements WasmNop+lower_CallishMachOp _ (MO_Prefetch_Data {}) _ _ = pure $ WasmStatements WasmNop+lower_CallishMachOp lbl (MO_Memcpy {}) [] xs = do+  ty_word_cmm <- wasmWordCmmTypeM+  lower_CmmUnsafeForeignCall_Drop lbl "memcpy" ty_word_cmm xs+lower_CallishMachOp lbl (MO_Memset {}) [] xs = do+  ty_word_cmm <- wasmWordCmmTypeM+  lower_CmmUnsafeForeignCall_Drop lbl "memset" ty_word_cmm xs+lower_CallishMachOp lbl (MO_Memmove {}) [] xs = do+  ty_word_cmm <- wasmWordCmmTypeM+  lower_CmmUnsafeForeignCall_Drop lbl "memmove" ty_word_cmm xs+lower_CallishMachOp lbl (MO_Memcmp {}) rs xs =+  lower_CmmUnsafeForeignCall+    lbl+    (Left "memcmp")+    CmmMayReturn+    rs+    xs+lower_CallishMachOp lbl (MO_PopCnt w0) rs xs =+  lower_CmmUnsafeForeignCall+    lbl+    (Left $ fromString $ "hs_popcnt" <> show (widthInBits w0))+    CmmMayReturn+    rs+    xs+lower_CallishMachOp lbl (MO_Pdep w0) rs xs =+  lower_CmmUnsafeForeignCall+    lbl+    (Left $ fromString $ "hs_pdep" <> show (widthInBits w0))+    CmmMayReturn+    rs+    xs+lower_CallishMachOp lbl (MO_Pext w0) rs xs =+  lower_CmmUnsafeForeignCall+    lbl+    (Left $ fromString $ "hs_pext" <> show (widthInBits w0))+    CmmMayReturn+    rs+    xs+lower_CallishMachOp lbl (MO_Clz w0) rs xs =+  lower_CmmUnsafeForeignCall+    lbl+    (Left $ fromString $ "hs_clz" <> show (widthInBits w0))+    CmmMayReturn+    rs+    xs+lower_CallishMachOp lbl (MO_Ctz w0) rs xs =+  lower_CmmUnsafeForeignCall+    lbl+    (Left $ fromString $ "hs_ctz" <> show (widthInBits w0))+    CmmMayReturn+    rs+    xs+lower_CallishMachOp lbl (MO_BSwap w0) rs xs =+  lower_CmmUnsafeForeignCall+    lbl+    (Left $ fromString $ "hs_bswap" <> show (widthInBits w0))+    CmmMayReturn+    rs+    xs+lower_CallishMachOp lbl (MO_BRev w0) rs xs =+  lower_CmmUnsafeForeignCall+    lbl+    (Left $ fromString $ "hs_bitrev" <> show (widthInBits w0))+    CmmMayReturn+    rs+    xs+lower_CallishMachOp lbl (MO_AtomicRMW w0 op) rs xs =+  lower_CmmUnsafeForeignCall+    lbl+    ( Left $+        fromString $+          ( case op of+              AMO_Add -> "hs_atomic_add"+              AMO_Sub -> "hs_atomic_sub"+              AMO_And -> "hs_atomic_and"+              AMO_Nand -> "hs_atomic_nand"+              AMO_Or -> "hs_atomic_or"+              AMO_Xor -> "hs_atomic_xor"+          )+            <> show (widthInBits w0)+    )+    CmmMayReturn+    rs+    xs+lower_CallishMachOp lbl (MO_AtomicRead w0) [reg] [ptr] = do+  SomeWasmExpr ty (WasmExpr ret_instr) <-+    lower_CmmLoad+      lbl+      ptr+      (cmmBits w0)+      NaturallyAligned+  ri <- onCmmLocalReg_Typed ty reg+  pure $ WasmStatements $ ret_instr `WasmConcat` WasmLocalSet ty ri+lower_CallishMachOp lbl (MO_AtomicWrite _) [] [ptr, val] =+  lower_CmmStore lbl ptr val NaturallyAligned+lower_CallishMachOp lbl (MO_Cmpxchg w0) rs xs = lower_MO_Cmpxchg lbl w0 rs xs+lower_CallishMachOp lbl (MO_Xchg w0) rs xs =+  lower_CmmUnsafeForeignCall+    lbl+    (Left $ fromString $ "hs_xchg" <> show (widthInBits w0))+    CmmMayReturn+    rs+    xs+lower_CallishMachOp lbl MO_SuspendThread rs xs =+  lower_CmmUnsafeForeignCall+    lbl+    (Left "suspendThread")+    CmmMayReturn+    rs+    xs+lower_CallishMachOp lbl MO_ResumeThread rs xs =+  lower_CmmUnsafeForeignCall+    lbl+    (Left "resumeThread")+    CmmMayReturn+    rs+    xs+lower_CallishMachOp _ _ _ _ = panic "lower_CallishMachOp: unreachable"++-- | Lower a ccall, but drop the result by assigning it to an unused+-- local. This is only used for lowering 'MO_Memcpy' and such, where+-- the libc functions do have a return value, but the corresponding+-- 'CallishMachOp' does not expect one.+lower_CmmUnsafeForeignCall_Drop ::+  CLabel ->+  SymName ->+  CmmType ->+  [CmmActual] ->+  WasmCodeGenM w (WasmStatements w)+lower_CmmUnsafeForeignCall_Drop lbl sym_callee ret_cmm_ty arg_exprs = do+  ret_uniq <- wasmUniq+  let ret_local = LocalReg ret_uniq ret_cmm_ty+  lower_CmmUnsafeForeignCall+    lbl+    (Left sym_callee)+    CmmMayReturn+    [ret_local]+    arg_exprs++-- | Lower a 'CmmUnsafeForeignCall'. The target is 'Either' a symbol,+-- which translates to a direct @call@, or an expression, which+-- translates to a @call_indirect@. The callee function signature is+-- inferred from the passed in arguments here.+lower_CmmUnsafeForeignCall ::+  CLabel ->+  (Either SymName CmmExpr) ->+  CmmReturnInfo ->+  [CmmFormal] ->+  [CmmActual] ->+  WasmCodeGenM+    w+    (WasmStatements w)+lower_CmmUnsafeForeignCall lbl target ret_info ret_locals arg_exprs = do+  SomeWasmPreCCall arg_tys args_instr <-+    foldrM+      ( \arg_expr (SomeWasmPreCCall acc_tys acc_instr) -> do+          SomeWasmExpr arg_ty (WasmExpr arg_instr) <-+            lower_CmmExpr lbl arg_expr+          pure $+            SomeWasmPreCCall (arg_ty `TypeListCons` acc_tys) $+              arg_instr `WasmConcat` acc_instr+      )+      (SomeWasmPreCCall TypeListNil WasmNop)+      arg_exprs+  SomeWasmPostCCall ret_tys ret_instr <-+    foldrM+      ( \reg (SomeWasmPostCCall acc_tys acc_instr) -> do+          (reg_i, SomeWasmType reg_ty) <- onCmmLocalReg reg+          pure $+            SomeWasmPostCCall (reg_ty `TypeListCons` acc_tys) $+              acc_instr `WasmConcat` WasmLocalSet reg_ty reg_i+      )+      (SomeWasmPostCCall TypeListNil WasmNop)+      ret_locals+  case target of+    Left sym_callee -> do+      platform <- wasmPlatformM+      let arg_cmm_tys = map (cmmExprType platform) arg_exprs+          ret_cmm_tys = map localRegType ret_locals+      onFuncSym sym_callee arg_cmm_tys ret_cmm_tys+      pure $+        WasmStatements $+          args_instr+            `WasmConcat` WasmCCall sym_callee+            `WasmConcat` ( case ret_info of+                             CmmMayReturn -> ret_instr+                             CmmNeverReturns -> WasmUnreachable+                         )+    Right fptr_callee -> do+      (WasmExpr instr_callee, _) <- lower_CmmExpr_Ptr lbl fptr_callee+      pure $+        WasmStatements $+          args_instr+            `WasmConcat` instr_callee+            `WasmConcat` WasmCCallIndirect arg_tys ret_tys+            `WasmConcat` ( case ret_info of+                             CmmMayReturn -> ret_instr+                             CmmNeverReturns -> WasmUnreachable+                         )++-- | Lower a 'CmmStore'.+lower_CmmStore ::+  CLabel ->+  CmmExpr ->+  CmmExpr ->+  AlignmentSpec ->+  WasmCodeGenM+    w+    (WasmStatements w)+lower_CmmStore lbl ptr val align = do+  platform <- wasmPlatformM+  (WasmExpr ptr_instr, o) <- lower_CmmExpr_Ptr lbl ptr+  let ty_cmm = cmmExprType platform val+  SomeWasmExpr ty (WasmExpr val_instr) <- lower_CmmExpr lbl val+  pure $+    WasmStatements $+      ptr_instr+        `WasmConcat` val_instr+        `WasmConcat` WasmStore ty (wasmMemoryNarrowing ty ty_cmm) o align++-- | Lower a single Cmm action.+lower_CmmAction :: CLabel -> CmmNode O O -> WasmCodeGenM w (WasmStatements w)+lower_CmmAction lbl act = do+  ty_word <- wasmWordTypeM+  platform <- wasmPlatformM+  case act of+    CmmComment {} -> pure $ WasmStatements WasmNop+    CmmTick {} -> pure $ WasmStatements WasmNop+    CmmUnwind {} -> pure $ WasmStatements WasmNop+    CmmAssign (CmmLocal reg) e -> do+      (i, SomeWasmType ty_reg) <- onCmmLocalReg reg+      WasmExpr instrs <- lower_CmmExpr_Typed lbl ty_reg e+      pure $ WasmStatements $ instrs `WasmConcat` WasmLocalSet ty_reg i+    CmmAssign (CmmGlobal reg) e+      | BaseReg <- reg -> pure $ WasmStatements WasmNop+      | Just (sym_global, SomeWasmType ty_reg) <-+          globalInfoFromCmmGlobalReg ty_word reg -> do+          WasmExpr instrs <- lower_CmmExpr_Typed lbl ty_reg e+          pure $+            WasmStatements $+              instrs `WasmConcat` WasmGlobalSet ty_reg sym_global+      | otherwise -> do+          (WasmExpr ptr_instr, o) <-+            lower_CmmExpr_Ptr lbl $ get_GlobalReg_addr platform reg+          SomeWasmExpr ty_e (WasmExpr instrs) <- lower_CmmExpr lbl e+          pure $+            WasmStatements $+              ptr_instr+                `WasmConcat` instrs+                `WasmConcat` WasmStore ty_e Nothing o NaturallyAligned+    CmmStore ptr val align -> lower_CmmStore lbl ptr val align+    CmmUnsafeForeignCall+      ( ForeignTarget+          (CmmLit (CmmLabel lbl_callee))+          (ForeignConvention conv _ _ ret_info)+        )+      ret_locals+      arg_exprs+        | conv `elem` [CCallConv, CApiConv] ->+            lower_CmmUnsafeForeignCall+              lbl+              (Left $ symNameFromCLabel lbl_callee)+              ret_info+              ret_locals+              arg_exprs+    CmmUnsafeForeignCall+      (ForeignTarget target_expr (ForeignConvention conv _ _ ret_info))+      ret_locals+      arg_exprs+        | conv `elem` [CCallConv, CApiConv] ->+            lower_CmmUnsafeForeignCall+              lbl+              (Right target_expr)+              ret_info+              ret_locals+              arg_exprs+    CmmUnsafeForeignCall (PrimTarget op) ret_locals arg_exprs ->+      lower_CallishMachOp lbl op ret_locals arg_exprs+    _ -> panic "lower_CmmAction: unreachable"++-- | Lower a block of Cmm actions.+lower_CmmActions ::+  CLabel ->+  Label ->+  Block CmmNode O O ->+  WasmCodeGenM+    w+    (WasmStatements w)+lower_CmmActions lbl _ blk =+  foldlM+    ( \(WasmStatements acc) act ->+        (\(WasmStatements stmts) -> WasmStatements $ acc `WasmConcat` stmts)+          <$> lower_CmmAction lbl act+    )+    (WasmStatements WasmNop)+    acts+  where+    acts = blockToList blk++-- | Lower a 'CmmGraph'.+lower_CmmGraph :: CLabel -> CmmGraph -> WasmCodeGenM w (FuncBody w)+lower_CmmGraph lbl g = do+  ty_word <- wasmWordTypeM+  platform <- wasmPlatformM+  body <-+    structuredControl+      platform+      (\_ -> lower_CmmExpr_Typed lbl ty_word)+      (lower_CmmActions lbl)+      g+  locals <- wasmStateM $ \s ->+    (#+      map snd $ detEltsUFM $ localRegs s,+      s {localRegs = emptyUFM, localRegsCount = 0}+    #)+  pure FuncBody {funcLocals = locals, funcBody = wasmControlCast $ body}++-- | Invoked once for each 'CLabel' which indexes a 'CmmData' or+-- 'CmmProc'.+onTopSym :: CLabel -> WasmCodeGenM w ()+onTopSym lbl = case sym_vis of+  SymDefault -> wasmModifyM $ \s ->+    s+      { defaultSyms =+          IS.insert+            (getKey $ getUnique sym)+            $ defaultSyms s+      }+  _ -> pure ()+  where+    sym = symNameFromCLabel lbl++    sym_vis = symVisibilityFromCLabel lbl++-- | Invoked for each function 'CLabel' with known type (e.g. a+-- 'CmmProc', or callee of 'CmmUnsafeForeignCall').+onFuncSym :: SymName -> [CmmType] -> [CmmType] -> WasmCodeGenM w ()+onFuncSym sym arg_tys ret_tys = wasmModifyM $+  \s@WasmCodeGenState {..} ->+    s+      { funcTypes =+          addToUniqMap+            funcTypes+            sym+            ( map someWasmTypeFromCmmType arg_tys,+              map someWasmTypeFromCmmType ret_tys+            )+      }++-- | Invoked for all other 'CLabel's along the way, e.g. in+-- 'CmmStatic's or 'CmmExpr's.+onAnySym :: CLabel -> WasmCodeGenM w ()+onAnySym lbl = case sym_kind of+  SymFunc -> wasmModifyM $ \s@WasmCodeGenState {..} ->+    s {funcTypes = addToUniqMap_C const funcTypes sym ([], [])}+  _ -> pure ()+  where+    sym = symNameFromCLabel lbl++    sym_kind = symKindFromCLabel lbl++-- | Invoked for each 'LocalReg', returning its wasm local id and+-- representation type.+onCmmLocalReg :: LocalReg -> WasmCodeGenM w LocalInfo+onCmmLocalReg reg = wasmStateM $ \s@WasmCodeGenState {..} ->+  let reg_info =+        (localRegsCount, someWasmTypeFromCmmType $ localRegType reg)+   in case addToUFM_L (\_ i _ -> i) reg reg_info localRegs of+        (Just i, _) -> (# i, s #)+        (_, localRegs') ->+          (#+            reg_info,+            s+              { localRegs = localRegs',+                localRegsCount =+                  localRegsCount + 1+              }+          #)++-- | Invoked for each 'LocalReg' with expected representation type,+-- only returning its wasm local id.+onCmmLocalReg_Typed :: WasmTypeTag t -> LocalReg -> WasmCodeGenM w Int+onCmmLocalReg_Typed ty reg = do+  (i, SomeWasmType ty') <- onCmmLocalReg reg+  if+      | Just Refl <- ty' `testEquality` ty -> pure i+      | otherwise -> panic "onCmmLocalReg_Typed: unreachable"++-- | Invoked for dtors. We don't bother to implement dtors yet;+-- there's no native @.fini_array@ support for wasm, and the way+-- @clang@ handles dtors is generating a ctor that calls @atexit()@+-- for dtors. Which makes some sense, but we don't need to do the same+-- thing yet.+onFini :: [SymName] -> WasmCodeGenM w ()+onFini syms = do+  let n_finis = length syms+  when (n_finis /= 0) $ panic "dtors unsupported by wasm32 NCG"++-- | Invoked for ctors and dtors.+onCmmInitFini :: InitOrFini -> [CLabel] -> WasmCodeGenM w ()+onCmmInitFini iof lbls = do+  for_ lbls $ \lbl -> onFuncSym (symNameFromCLabel lbl) [] []+  case iof of+    IsInitArray -> wasmModifyM $ \s -> s {ctors = syms <> ctors s}+    IsFiniArray -> onFini syms+  where+    syms = map symNameFromCLabel lbls++-- | Invoked for each data section.+onCmmData :: CLabel -> Section -> [CmmStatic] -> WasmCodeGenM w ()+onCmmData lbl s statics = do+  ty_word <- wasmWordTypeM+  onTopSym lbl+  cs <- for statics lower_CmmStatic+  let sym = symNameFromCLabel lbl+      sec =+        DataSection+          { dataSectionKind =+              dataSectionKindFromCmmSection s,+            dataSectionAlignment =+              alignmentFromCmmSection ty_word lbl,+            dataSectionContents =+              case cs of+                [DataASCII buf] -> [DataASCII $ buf `BS.snoc` 0]+                [DataIncBin p l] -> [DataIncBin p l, DataI8 0]+                _ -> cs+          }+  wasmModifyM $ \s ->+    s+      { dataSections =+          addToUniqMap (dataSections s) sym sec+      }++-- | Invoked for each 'CmmProc'.+onCmmProc :: CLabel -> CmmGraph -> WasmCodeGenM w ()+onCmmProc lbl g = do+  ty_word <- wasmWordCmmTypeM+  onTopSym lbl+  onFuncSym sym [] [ty_word]+  body <- lower_CmmGraph lbl g+  wasmModifyM $ \s -> s {funcBodies = addToUniqMap (funcBodies s) sym body}+  where+    sym = symNameFromCLabel lbl++-- | Invoked for each 'RawCmmDecl'.+onCmmDecl :: RawCmmDecl -> WasmCodeGenM w ()+onCmmDecl decl+  | Just (iof, lbls) <- isInitOrFiniArray decl = onCmmInitFini iof lbls+onCmmDecl (CmmData s (CmmStaticsRaw lbl statics)) = onCmmData lbl s statics+onCmmDecl (CmmProc _ lbl _ g) = onCmmProc lbl g++-- | Invoked for each 'RawCmmGroup'.+onCmmGroup :: RawCmmGroup -> WasmCodeGenM w ()+onCmmGroup cmms = wasmStateM $ \s0 ->+  (# (), foldl' (\s cmm -> wasmExecM (onCmmDecl cmm) s) s0 cmms #)
+ compiler/GHC/CmmToAsm/Wasm/Types.hs view
@@ -0,0 +1,452 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE Strict #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UndecidableInstances #-}++module GHC.CmmToAsm.Wasm.Types+  ( WasmType (..),+    WasmTypeTag (..),+    SomeWasmType (..),+    TypeList (..),+    someWasmTypesFromTypeList,+    WasmFunctionType (..),+    SymName (..),+    SymVisibility (..),+    SymKind (..),+    DataSectionKind (..),+    DataSectionContent (..),+    DataSection (..),+    GlobalInfo,+    LocalInfo,+    FuncBody (..),+    Signage (..),+    WasmInstr (..),+    WasmExpr (..),+    SomeWasmExpr (..),+    WasmStatements (..),+    WasmControl (..),+    BrTableInterval (..),+    wasmControlCast,+    WasmCodeGenState (..),+    initialWasmCodeGenState,+    WasmCodeGenM (..),+    wasmGetsM,+    wasmPlatformM,+    wasmWordTypeM,+    wasmWordCmmTypeM,+    wasmStateM,+    wasmModifyM,+    wasmExecM,+    wasmUniq,+  )+where++import Control.Applicative+import Data.ByteString (ByteString)+import Data.Coerce+import Data.Functor+import qualified Data.IntSet as IS+import Data.Kind+import Data.String+import Data.Type.Equality+import GHC.Cmm+import GHC.Data.FastString+import GHC.Float+import GHC.Platform+import GHC.Prelude+import GHC.Types.Basic+import GHC.Types.Unique+import GHC.Types.Unique.FM+import GHC.Types.Unique.Map+import GHC.Types.Unique.Supply+import GHC.Utils.Monad.State.Strict+import GHC.Utils.Outputable hiding ((<>))+import Unsafe.Coerce++-- | WebAssembly type of a WebAssembly value that WebAssembly code+-- could either expect on the evaluation stack or leave on the+-- evaluation stack.+data WasmType = I32 | I64 | F32 | F64++-- | Singleton type useful for programming with `WasmType` at the type+-- level.+data WasmTypeTag :: WasmType -> Type where+  TagI32 :: WasmTypeTag 'I32+  TagI64 :: WasmTypeTag 'I64+  TagF32 :: WasmTypeTag 'F32+  TagF64 :: WasmTypeTag 'F64++deriving instance Show (WasmTypeTag t)++instance TestEquality WasmTypeTag where+  TagI32 `testEquality` TagI32 = Just Refl+  TagI64 `testEquality` TagI64 = Just Refl+  TagF32 `testEquality` TagF32 = Just Refl+  TagF64 `testEquality` TagF64 = Just Refl+  _ `testEquality` _ = Nothing++data SomeWasmType where+  SomeWasmType :: WasmTypeTag t -> SomeWasmType++instance Eq SomeWasmType where+  SomeWasmType ty0 == SomeWasmType ty1+    | Just Refl <- ty0 `testEquality` ty1 = True+    | otherwise = False++-- | List of WebAssembly types used to describe the sequence of+-- WebAssembly values that a block of code may expect on the stack or+-- leave on the stack.+data TypeList :: [WasmType] -> Type where+  TypeListNil :: TypeList '[]+  TypeListCons :: WasmTypeTag t -> TypeList ts -> TypeList (t : ts)++someWasmTypesFromTypeList :: TypeList ts -> [SomeWasmType]+someWasmTypesFromTypeList TypeListNil = []+someWasmTypesFromTypeList (ty `TypeListCons` tys) =+  SomeWasmType ty : someWasmTypesFromTypeList tys++-- | The type of a WebAssembly function, loop, block, or conditional.+-- This type says what values the code expects to pop off the stack+-- and what values it promises to push.  The WebAssembly standard+-- requires that this type appear explicitly in the code.+data WasmFunctionType pre post = WasmFunctionType {ft_pops :: TypeList pre, ft_pushes :: TypeList post}++-- | For simplicity, we record other metadata in 'WasmCodeGenState' by+-- need, instead of carrying them along with 'SymName'.+newtype SymName = SymName FastString+  deriving (Eq, IsString, Show, Uniquable) via FastString+  deriving (Ord) via LexicalFastString++data SymVisibility+  = -- | Not defined in the current compilation unit.+    --+    -- @[ undefined binding=global vis=default ]@+    SymUndefined+  | -- | Defined, not visible to other compilation units.+    --+    -- @[ binding=local vis=default ]@+    SymStatic+  | -- | Defined, visible to other compilation units.+    --+    -- Adds @.hidden@ & @.globl@ directives in the output assembly.+    --+    -- @[ binding=global vis=hidden ]@+    SymDefault++-- | Represents whether a symbol is a data symbol or a function+-- symbol. Unlike linkers for other targets, @wasm-ld@ does panic at+-- link-time if it finds symbol kind inconsistency between the+-- definition site and other use sites.+--+-- Currently we solely rely on 'isCFunctionLabel' to determine a+-- symbol's kind, but it does take extra effort to make it work. The+-- main source of inconsistency arises from hand-written Cmm sources,+-- where it's possible to refer to external entities like @xxx_info@+-- and @xxx_closure@ without explicit @import CLOSURE@ declarations.+-- The Cmm parser will implicitly assume those are foreign function+-- labels, and then this will break the WebAssembly backend. #22368+-- provides more context on this issue.+--+-- tl;dr for any GHC contributor that accidentally triggers @wasm-ld@+-- errors when hacking Cmm: whatever data symbols are used in new+-- code, just add the corresponding @import CLOSURE@ declarations at+-- the top of that Cmm file.+data SymKind = SymData | SymFunc+  deriving (Eq)++-- | WebAssembly doesn't really have proper read-only memory regions+-- yet. Neverthless we add the .rodata logic here, wasm-ld will+-- aggregate all .rodata sections into a single one, which adds+-- possibility for runtime checks later, either via a customized+-- runtime, or via code instrumentation. See+-- <https://github.com/llvm/llvm-project/blob/b296aed8ae239c20ebdd7969e978f8d2a3b9c178/lld/wasm/Writer.cpp#L856>+data DataSectionKind = SectionData | SectionROData++-- | Neither Cmm or Wasm type system takes integer signedness into+-- account, therefore we always round up a 'CmmLit' to the right width+-- and handle it as an untyped integer.+data DataSectionContent+  = DataI8 Integer+  | DataI16 Integer+  | DataI32 Integer+  | DataI64 Integer+  | DataF32 Float+  | DataF64 Double+  | DataSym SymName Int+  | DataSkip Int+  | DataASCII ByteString+  | DataIncBin FilePath Int++data DataSection = DataSection+  { dataSectionKind :: DataSectionKind,+    dataSectionAlignment ::+      Alignment,+    dataSectionContents :: [DataSectionContent]+  }++-- | We need to remember the symbols. Determinism is achieved by+-- sorting symbols before writing the assembly.+type SymMap = UniqMap SymName++-- | No need to remember the symbols.+type SymSet = IS.IntSet++type GlobalInfo = (SymName, SomeWasmType)++type LocalInfo = (Int, SomeWasmType)++data FuncBody w = FuncBody+  { funcLocals :: [SomeWasmType],+    -- | Most are Cmm functions, but may also contain synthesized+    -- function of other types, sigh.+    funcBody :: WasmControl (WasmStatements w) (WasmExpr w w) '[] '[w]+  }++data Signage = Signed | Unsigned++-- | The @w@ type variable in the Wasm IR stands for "platform word+-- type", so 'TagI32' on wasm32, and 'TagI64' on wasm64. This way, we+-- can make the codegen logic work on both wasm32/wasm64 in a+-- type-safe manner.+data WasmInstr :: WasmType -> [WasmType] -> [WasmType] -> Type where+  WasmComment :: String -> WasmInstr w pre pre+  WasmNop :: WasmInstr w pre pre+  WasmDrop :: WasmInstr w (t : pre) pre+  WasmUnreachable :: WasmInstr w pre post+  WasmConst :: WasmTypeTag t -> Integer -> WasmInstr w pre (t : pre)+  WasmSymConst :: SymName -> WasmInstr w pre (w : pre)+  WasmLoad ::+    WasmTypeTag t ->+    Maybe Int ->+    Signage ->+    Int ->+    AlignmentSpec ->+    WasmInstr w (w : pre) (t : pre)+  WasmStore ::+    WasmTypeTag t ->+    Maybe Int ->+    Int ->+    AlignmentSpec ->+    WasmInstr+      w+      (t : w : pre)+      pre+  WasmGlobalGet :: WasmTypeTag t -> SymName -> WasmInstr w pre (t : pre)+  WasmGlobalSet :: WasmTypeTag t -> SymName -> WasmInstr w (t : pre) pre+  WasmLocalGet :: WasmTypeTag t -> Int -> WasmInstr w pre (t : pre)+  WasmLocalSet :: WasmTypeTag t -> Int -> WasmInstr w (t : pre) pre+  WasmLocalTee :: WasmTypeTag t -> Int -> WasmInstr w (t : pre) (t : pre)+  WasmCCall :: SymName -> WasmInstr w pre post+  WasmCCallIndirect ::+    TypeList arg_tys ->+    TypeList ret_tys ->+    WasmInstr+      w+      (w : pre)+      post+  WasmConcat ::+    WasmInstr w pre mid ->+    WasmInstr w mid post ->+    WasmInstr w pre post+  WasmReinterpret ::+    WasmTypeTag t0 ->+    WasmTypeTag t1 ->+    WasmInstr+      w+      (t0 : pre)+      (t1 : pre)+  WasmTruncSat ::+    Signage ->+    WasmTypeTag t0 ->+    WasmTypeTag t1 ->+    WasmInstr+      w+      (t0 : pre)+      (t1 : pre)+  WasmConvert ::+    Signage ->+    WasmTypeTag t0 ->+    WasmTypeTag t1 ->+    WasmInstr+      w+      (t0 : pre)+      (t1 : pre)+  WasmAdd :: WasmTypeTag t -> WasmInstr w (t : t : pre) (t : pre)+  WasmSub :: WasmTypeTag t -> WasmInstr w (t : t : pre) (t : pre)+  WasmMul :: WasmTypeTag t -> WasmInstr w (t : t : pre) (t : pre)+  WasmDiv :: Signage -> WasmTypeTag t -> WasmInstr w (t : t : pre) (t : pre)+  WasmRem :: Signage -> WasmTypeTag t -> WasmInstr w (t : t : pre) (t : pre)+  WasmAnd :: WasmTypeTag t -> WasmInstr w (t : t : pre) (t : pre)+  WasmOr :: WasmTypeTag t -> WasmInstr w (t : t : pre) (t : pre)+  WasmXor :: WasmTypeTag t -> WasmInstr w (t : t : pre) (t : pre)+  WasmEq :: WasmTypeTag t -> WasmInstr w (t : t : pre) (w : pre)+  WasmNe :: WasmTypeTag t -> WasmInstr w (t : t : pre) (w : pre)+  WasmLt :: Signage -> WasmTypeTag t -> WasmInstr w (t : t : pre) (w : pre)+  WasmGt :: Signage -> WasmTypeTag t -> WasmInstr w (t : t : pre) (w : pre)+  WasmLe :: Signage -> WasmTypeTag t -> WasmInstr w (t : t : pre) (w : pre)+  WasmGe :: Signage -> WasmTypeTag t -> WasmInstr w (t : t : pre) (w : pre)+  WasmShl :: WasmTypeTag t -> WasmInstr w (t : t : pre) (t : pre)+  WasmShr :: Signage -> WasmTypeTag t -> WasmInstr w (t : t : pre) (t : pre)+  WasmI32Extend8S :: WasmInstr w ('I32 : pre) ('I32 : pre)+  WasmI32Extend16S :: WasmInstr w ('I32 : pre) ('I32 : pre)+  WasmI64Extend8S :: WasmInstr w ('I64 : pre) ('I64 : pre)+  WasmI64Extend16S :: WasmInstr w ('I64 : pre) ('I64 : pre)+  WasmI64Extend32S :: WasmInstr w ('I64 : pre) ('I64 : pre)+  WasmI64ExtendI32 :: Signage -> WasmInstr w ('I32 : pre) ('I64 : pre)+  WasmI32WrapI64 :: WasmInstr w ('I64 : pre) ('I32 : pre)+  WasmF32DemoteF64 :: WasmInstr w ('F64 : pre) ('F32 : pre)+  WasmF64PromoteF32 :: WasmInstr w ('F32 : pre) ('F64 : pre)+  WasmAbs :: WasmTypeTag t -> WasmInstr w (t : pre) (t : pre)+  WasmCond :: WasmInstr w pre pre -> WasmInstr w (w : pre) pre++newtype WasmExpr w t = WasmExpr (forall pre. WasmInstr w pre (t : pre))++data SomeWasmExpr w where+  SomeWasmExpr :: WasmTypeTag t -> WasmExpr w t -> SomeWasmExpr w++newtype WasmStatements w = WasmStatements (forall pre. WasmInstr w pre pre)++-- | Representation of WebAssembly control flow.+-- Normally written as+-- @+--   WasmControl s e pre post+-- @+-- Type parameter `s` is the type of (unspecified) statements.+-- It might be instantiated with an open Cmm block or with a sequence+-- of Wasm instructions.+-- Parameter `e` is the type of expressions.+-- Parameter `pre` represents the values that are expected on the+-- WebAssembly stack when the code runs, and `post` represents+-- the state of the stack on completion.+data WasmControl :: Type -> Type -> [WasmType] -> [WasmType] -> Type where+  WasmPush :: WasmTypeTag t -> e -> WasmControl s e stack (t : stack)+  WasmBlock ::+    WasmFunctionType pre post ->+    WasmControl s e pre post ->+    WasmControl s e pre post+  WasmLoop ::+    WasmFunctionType pre post ->+    WasmControl s e pre post ->+    WasmControl s e pre post+  WasmIfTop ::+    WasmFunctionType pre post ->+    WasmControl s e pre post ->+    WasmControl s e pre post ->+    WasmControl s e ('I32 : pre) post+  WasmBr :: Int -> WasmControl s e dropped destination -- not typechecked+  WasmFallthrough :: WasmControl s e dropped destination+  -- generates no code, but has the same type as a branch+  WasmBrTable ::+    e ->+    BrTableInterval -> -- for testing+    [Int] -> -- targets+    Int -> -- default target+    WasmControl s e dropped destination+  -- invariant: the table interval is contained+  -- within [0 .. pred (length targets)]+  WasmReturnTop ::+    WasmTypeTag t ->+    WasmControl s e (t : t1star) t2star -- as per type system+  WasmActions ::+    s ->+    WasmControl s e stack stack -- basic block: one entry, one exit+  WasmSeq ::+    WasmControl s e pre mid ->+    WasmControl s e mid post ->+    WasmControl s e pre post++data BrTableInterval = BrTableInterval {bti_lo :: Integer, bti_count :: Integer}+  deriving (Show)++instance Outputable BrTableInterval where+  ppr range =+    brackets $+      hcat+        [integer (bti_lo range), text "..", integer hi]+    where+      hi = bti_lo range + bti_count range - 1++wasmControlCast :: WasmControl s e pre post -> WasmControl s e pre' post'+wasmControlCast = unsafeCoerce++data WasmCodeGenState w = WasmCodeGenState+  { -- | Target platform+    wasmPlatform :: Platform,+    -- | Defined symbols with 'SymDefault' visibility.+    defaultSyms :: SymSet,+    -- | Function types, defined or not. There may exist a function+    -- whose type is unknown (e.g. as a function pointer), in that+    -- case we fall back to () -> (), it's imperfect but works with+    -- wasm-ld.+    funcTypes :: SymMap ([SomeWasmType], [SomeWasmType]),+    -- | Defined function bodies.+    funcBodies :: SymMap (FuncBody w),+    -- | Defined data sections.+    dataSections :: SymMap DataSection,+    -- | ctors in the current compilation unit.+    ctors :: [SymName],+    localRegs ::+      UniqFM LocalReg LocalInfo,+    localRegsCount ::+      Int,+    wasmUniqSupply :: UniqSupply+  }++initialWasmCodeGenState :: Platform -> UniqSupply -> WasmCodeGenState w+initialWasmCodeGenState platform us =+  WasmCodeGenState+    { wasmPlatform =+        platform,+      defaultSyms = IS.empty,+      funcTypes = emptyUniqMap,+      funcBodies =+        emptyUniqMap,+      dataSections = emptyUniqMap,+      ctors =+        [],+      localRegs = emptyUFM,+      localRegsCount = 0,+      wasmUniqSupply = us+    }++newtype WasmCodeGenM w a = WasmCodeGenM (State (WasmCodeGenState w) a)+  deriving newtype (Functor, Applicative, Monad)++wasmGetsM :: (WasmCodeGenState w -> a) -> WasmCodeGenM w a+wasmGetsM = coerce . gets++wasmPlatformM :: WasmCodeGenM w Platform+wasmPlatformM = wasmGetsM wasmPlatform++wasmWordTypeM :: WasmCodeGenM w (WasmTypeTag w)+wasmWordTypeM = wasmGetsM $ \s ->+  if target32Bit $ wasmPlatform s+    then unsafeCoerce TagI32+    else unsafeCoerce TagI64++wasmWordCmmTypeM :: WasmCodeGenM w CmmType+wasmWordCmmTypeM = wasmGetsM (bWord . wasmPlatform)++wasmStateM ::+  (WasmCodeGenState w -> (# a, WasmCodeGenState w #)) ->+  WasmCodeGenM w a+wasmStateM = coerce . State++wasmModifyM :: (WasmCodeGenState w -> WasmCodeGenState w) -> WasmCodeGenM w ()+wasmModifyM = coerce . modify++wasmExecM :: WasmCodeGenM w a -> WasmCodeGenState w -> WasmCodeGenState w+wasmExecM (WasmCodeGenM s) = execState s++wasmUniq :: WasmCodeGenM w Unique+wasmUniq = wasmStateM $+  \s@WasmCodeGenState {..} -> case takeUniqFromSupply wasmUniqSupply of+    (u, us) -> (# u, s {wasmUniqSupply = us} #)
+ compiler/GHC/CmmToAsm/Wasm/Utils.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Strict #-}++module GHC.CmmToAsm.Wasm.Utils+  ( naturalNarrowing,+    widthMax,+    detEltsUFM,+    detEltsUniqMap,+    builderCommas,+  )+where++import Data.ByteString.Builder+import Data.List (intersperse, sortOn)+import GHC.Cmm+import GHC.Prelude+import GHC.Types.Unique.FM+import GHC.Types.Unique.Map++naturalNarrowing :: Width -> Integer -> Integer+naturalNarrowing w i+  | i < 0 = narrowS w i+  | otherwise = narrowU w i++widthMax :: Width -> Integer+widthMax w = (1 `shiftL` widthInBits w) - 1++detEltsUFM :: Ord k => UniqFM k0 (k, a) -> [(k, a)]+detEltsUFM = sortOn fst . nonDetEltsUFM++detEltsUniqMap :: Ord k => UniqMap k a -> [(k, a)]+detEltsUniqMap = sortOn fst . nonDetEltsUniqMap++builderCommas :: (a -> Builder) -> [a] -> Builder+builderCommas f xs = mconcat (intersperse ", " (map f xs))
compiler/GHC/CmmToAsm/X86.hs view
@@ -33,7 +33,8 @@    , canShortcut               = X86.canShortcut    , shortcutStatics           = X86.shortcutStatics    , shortcutJump              = X86.shortcutJump-   , pprNatCmmDecl             = X86.pprNatCmmDecl config+   , pprNatCmmDeclS            = X86.pprNatCmmDecl config+   , pprNatCmmDeclH            = X86.pprNatCmmDecl config    , maxSpillSlots             = X86.maxSpillSlots config    , allocatableRegs           = X86.allocatableRegs platform    , ncgAllocMoreStack         = X86.allocMoreStack platform
compiler/GHC/CmmToAsm/X86/CodeGen.hs view
@@ -326,7 +326,7 @@        -> genForeignCall target result_regs args bid      _ -> (,Nothing) <$> case stmt of-      CmmComment s   -> return (unitOL (COMMENT $ ftext s))+      CmmComment s   -> return (unitOL (COMMENT s))       CmmTick {}     -> return nilOL        CmmUnwind regs -> do
compiler/GHC/CmmToAsm/X86/Instr.hs view
@@ -38,6 +38,7 @@ where  import GHC.Prelude+import GHC.Data.FastString  import GHC.CmmToAsm.X86.Cond import GHC.CmmToAsm.X86.Regs@@ -170,7 +171,7 @@  data Instr         -- comment pseudo-op-        = COMMENT SDoc+        = COMMENT FastString          -- location pseudo-op (file, line, col, name)         | LOCATION Int Int Int String@@ -868,7 +869,7 @@         case platformArch platform of             ArchX86    | needs_probe_call platform amount ->                            [ MOV II32 (OpImm (ImmInt amount)) (OpReg eax)-                           , CALL (Left $ strImmLit "___chkstk_ms") [eax]+                           , CALL (Left $ strImmLit (fsLit "___chkstk_ms")) [eax]                            , SUB II32 (OpReg eax) (OpReg esp)                            ]                        | otherwise ->@@ -877,7 +878,7 @@                            ]             ArchX86_64 | needs_probe_call platform amount ->                            [ MOV II64 (OpImm (ImmInt amount)) (OpReg rax)-                           , CALL (Left $ strImmLit "___chkstk_ms") [rax]+                           , CALL (Left $ strImmLit (fsLit "___chkstk_ms")) [rax]                            , SUB II64 (OpReg rax) (OpReg rsp)                            ]                        | otherwise ->
compiler/GHC/CmmToAsm/X86/Ppr.hs view
@@ -1,5 +1,6 @@  {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE ScopedTypeVariables #-}  ----------------------------------------------------------------------------- --@@ -11,11 +12,7 @@  module GHC.CmmToAsm.X86.Ppr (         pprNatCmmDecl,-        pprData,         pprInstr,-        pprFormat,-        pprImm,-        pprDataItem, )  where@@ -39,6 +36,7 @@ import GHC.Cmm.Dataflow.Label import GHC.Cmm.BlockId import GHC.Cmm.CLabel+import GHC.Cmm.DebugBlock (pprUnwindTable)  import GHC.Types.Basic (Alignment, mkAlignment, alignmentBytes) import GHC.Types.Unique ( pprUniqueAlways )@@ -65,12 +63,12 @@ -- .subsections_via_symbols and -dead_strip can be found at -- <https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/Assembler/040-Assembler_Directives/asm_directives.html#//apple_ref/doc/uid/TP30000823-TPXREF101> -pprProcAlignment :: NCGConfig -> SDoc+pprProcAlignment :: IsDoc doc => NCGConfig -> doc pprProcAlignment config = maybe empty (pprAlign platform . mkAlignment) (ncgProcAlignment config)    where       platform = ncgPlatform config -pprNatCmmDecl :: NCGConfig -> NatCmmDecl (Alignment, RawCmmStatics) Instr -> SDoc+pprNatCmmDecl :: IsDoc doc => NCGConfig -> NatCmmDecl (Alignment, RawCmmStatics) Instr -> doc pprNatCmmDecl config (CmmData section dats) =   pprSectionAlign config section $$ pprDatas config dats @@ -85,7 +83,7 @@         pprProcLabel config lbl $$         pprLabel platform lbl $$ -- blocks guaranteed not null, so label needed         vcat (map (pprBasicBlock config top_info) blocks) $$-        ppWhen (ncgDwarfEnabled config) (pprBlockEndLabel platform lbl $$ pprProcEndLabel platform lbl) $$+        ppWhen (ncgDwarfEnabled config) (line (pprBlockEndLabel platform lbl) $$ line (pprProcEndLabel platform lbl)) $$         pprSizeDecl platform lbl      Just (CmmStaticsRaw info_lbl _) ->@@ -93,48 +91,51 @@       pprProcAlignment config $$       pprProcLabel config lbl $$       (if platformHasSubsectionsViaSymbols platform-          then pprAsmLabel platform (mkDeadStripPreventer info_lbl) <> colon+          then line (pprAsmLabel platform (mkDeadStripPreventer info_lbl) <> colon)           else empty) $$       vcat (map (pprBasicBlock config top_info) blocks) $$-      ppWhen (ncgDwarfEnabled config) (pprProcEndLabel platform info_lbl) $$+      ppWhen (ncgDwarfEnabled config) (line (pprProcEndLabel platform info_lbl)) $$       -- above: Even the first block gets a label, because with branch-chain       -- elimination, it might be the target of a goto.       (if platformHasSubsectionsViaSymbols platform        then -- See Note [Subsections Via Symbols]-                text "\t.long "+                line+              $ text "\t.long "             <+> pprAsmLabel platform info_lbl             <+> char '-'             <+> pprAsmLabel platform (mkDeadStripPreventer info_lbl)        else empty) $$       pprSizeDecl platform info_lbl+{-# SPECIALIZE pprNatCmmDecl :: NCGConfig -> NatCmmDecl (Alignment, RawCmmStatics) Instr -> SDoc #-}+{-# SPECIALIZE pprNatCmmDecl :: NCGConfig -> NatCmmDecl (Alignment, RawCmmStatics) Instr -> HDoc #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable  -- | Output an internal proc label. See Note [Internal proc labels] in CLabel.-pprProcLabel :: NCGConfig -> CLabel -> SDoc+pprProcLabel :: IsDoc doc => NCGConfig -> CLabel -> doc pprProcLabel config lbl   | ncgExposeInternalSymbols config   , Just lbl' <- ppInternalProcLabel (ncgThisModule config) lbl-  = lbl' <> colon+  = line (lbl' <> colon)   | otherwise   = empty -pprProcEndLabel :: Platform -> CLabel -- ^ Procedure name-                -> SDoc+pprProcEndLabel :: IsLine doc => Platform -> CLabel -- ^ Procedure name+                -> doc pprProcEndLabel platform lbl =     pprAsmLabel platform (mkAsmTempProcEndLabel lbl) <> colon -pprBlockEndLabel :: Platform -> CLabel -- ^ Block name-                 -> SDoc+pprBlockEndLabel :: IsLine doc => Platform -> CLabel -- ^ Block name+                 -> doc pprBlockEndLabel platform lbl =     pprAsmLabel platform (mkAsmTempEndLabel lbl) <> colon  -- | Output the ELF .size directive.-pprSizeDecl :: Platform -> CLabel -> SDoc+pprSizeDecl :: IsDoc doc => Platform -> CLabel -> doc pprSizeDecl platform lbl  = if osElfTarget (platformOS platform)-   then text "\t.size" <+> pprAsmLabel platform lbl <> text ", .-" <> pprAsmLabel platform lbl+   then line (text "\t.size" <+> pprAsmLabel platform lbl <> text ", .-" <> pprAsmLabel platform lbl)    else empty -pprBasicBlock :: NCGConfig -> LabelMap RawCmmStatics -> NatBasicBlock Instr -> SDoc+pprBasicBlock :: IsDoc doc => NCGConfig -> LabelMap RawCmmStatics -> NatBasicBlock Instr -> doc pprBasicBlock config info_env (BasicBlock blockid instrs)   = maybe_infotable $     pprLabel platform asmLbl $$@@ -142,8 +143,8 @@     ppWhen (ncgDwarfEnabled config) (       -- Emit both end labels since this may end up being a standalone       -- top-level block-      pprBlockEndLabel platform asmLbl-      <> pprProcEndLabel platform asmLbl+      line (pprBlockEndLabel platform asmLbl+         <> pprProcEndLabel platform asmLbl)     )   where     asmLbl = blockLbl blockid@@ -156,7 +157,7 @@            vcat (map (pprData config) info) $$            pprLabel platform infoLbl $$            c $$-           ppWhen (ncgDwarfEnabled config) (pprAsmLabel platform (mkAsmTempEndLabel infoLbl) <> colon)+           ppWhen (ncgDwarfEnabled config) (line (pprAsmLabel platform (mkAsmTempEndLabel infoLbl) <> colon))      -- Make sure the info table has the right .loc for the block     -- coming right after it. See Note [Info Offset]@@ -165,7 +166,7 @@       _other             -> empty  -pprDatas :: NCGConfig -> (Alignment, RawCmmStatics) -> SDoc+pprDatas :: IsDoc doc => NCGConfig -> (Alignment, RawCmmStatics) -> doc -- See Note [emit-time elimination of static indirections] in "GHC.Cmm.CLabel". pprDatas config (_, CmmStaticsRaw alias [CmmStaticLit (CmmLabel lbl), CmmStaticLit ind, _, _])   | lbl == mkIndStaticInfoLabel@@ -175,31 +176,32 @@   , Just ind' <- labelInd ind   , alias `mayRedirectTo` ind'   = pprGloblDecl (ncgPlatform config) alias-    $$ text ".equiv" <+> pprAsmLabel (ncgPlatform config) alias <> comma <> pprAsmLabel (ncgPlatform config) ind'+    $$ line (text ".equiv" <+> pprAsmLabel (ncgPlatform config) alias <> comma <> pprAsmLabel (ncgPlatform config) ind')  pprDatas config (align, (CmmStaticsRaw lbl dats))  = vcat (pprAlign platform align : pprLabel platform lbl : map (pprData config) dats)    where       platform = ncgPlatform config -pprData :: NCGConfig -> CmmStatic -> SDoc-pprData _config (CmmString str) = pprString str-pprData _config (CmmFileEmbed path) = pprFileEmbed path+pprData :: IsDoc doc => NCGConfig -> CmmStatic -> doc+pprData _config (CmmString str) = line (pprString str)+pprData _config (CmmFileEmbed path _) = line (pprFileEmbed path)  pprData config (CmmUninitialised bytes)- = let platform = ncgPlatform config+ = line+ $ let platform = ncgPlatform config    in if platformOS platform == OSDarwin          then text ".space " <> int bytes          else text ".skip "  <> int bytes  pprData config (CmmStaticLit lit) = pprDataItem config lit -pprGloblDecl :: Platform -> CLabel -> SDoc+pprGloblDecl :: IsDoc doc => Platform -> CLabel -> doc pprGloblDecl platform lbl   | not (externallyVisibleCLabel lbl) = empty-  | otherwise = text ".globl " <> pprAsmLabel platform lbl+  | otherwise = line (text ".globl " <> pprAsmLabel platform lbl) -pprLabelType' :: Platform -> CLabel -> SDoc+pprLabelType' :: IsLine doc => Platform -> CLabel -> doc pprLabelType' platform lbl =   if isCFunctionLabel lbl || functionOkInfoTable then     text "@function"@@ -257,21 +259,21 @@       isInfoTableLabel lbl && not (isCmmInfoTableLabel lbl) && not (isConInfoTableLabel lbl)  -pprTypeDecl :: Platform -> CLabel -> SDoc+pprTypeDecl :: IsDoc doc => Platform -> CLabel -> doc pprTypeDecl platform lbl     = if osElfTarget (platformOS platform) && externallyVisibleCLabel lbl-      then text ".type " <> pprAsmLabel platform lbl <> text ", " <> pprLabelType' platform lbl+      then line (text ".type " <> pprAsmLabel platform lbl <> text ", " <> pprLabelType' platform lbl)       else empty -pprLabel :: Platform -> CLabel -> SDoc+pprLabel :: IsDoc doc => Platform -> CLabel -> doc pprLabel platform lbl =    pprGloblDecl platform lbl    $$ pprTypeDecl platform lbl-   $$ (pprAsmLabel platform lbl <> colon)+   $$ line (pprAsmLabel platform lbl <> colon) -pprAlign :: Platform -> Alignment -> SDoc+pprAlign :: IsDoc doc => Platform -> Alignment -> doc pprAlign platform alignment-        = text ".align " <> int (alignmentOn platform)+        = line $ text ".align " <> int (alignmentOn platform)   where         bytes = alignmentBytes alignment         alignmentOn platform = if platformOS platform == OSDarwin@@ -285,7 +287,7 @@         log2 8 = 3         log2 n = 1 + log2 (n `quot` 2) -pprReg :: Platform -> Format -> Reg -> SDoc+pprReg :: forall doc. IsLine doc => Platform -> Format -> Reg -> doc pprReg platform f r   = case r of       RegReal    (RealRegSingle i) ->@@ -297,7 +299,7 @@       RegVirtual (VirtualRegD  u)  -> text "%vD_"   <> pprUniqueAlways u    where-    ppr32_reg_no :: Format -> Int -> SDoc+    ppr32_reg_no :: Format -> Int -> doc     ppr32_reg_no II8   = ppr32_reg_byte     ppr32_reg_no II16  = ppr32_reg_word     ppr32_reg_no _     = ppr32_reg_long@@ -327,7 +329,7 @@          _  -> ppr_reg_float i       } -    ppr64_reg_no :: Format -> Int -> SDoc+    ppr64_reg_no :: Format -> Int -> doc     ppr64_reg_no II8   = ppr64_reg_byte     ppr64_reg_no II16  = ppr64_reg_word     ppr64_reg_no II32  = ppr64_reg_long@@ -385,7 +387,7 @@         _  -> ppr_reg_float i       } -ppr_reg_float :: Int -> SDoc+ppr_reg_float :: IsLine doc => Int -> doc ppr_reg_float i = case i of         16 -> text "%xmm0" ;   17 -> text "%xmm1"         18 -> text "%xmm2" ;   19 -> text "%xmm3"@@ -397,7 +399,7 @@         30 -> text "%xmm14";   31 -> text "%xmm15"         _  -> text "very naughty x86 register" -pprFormat :: Format -> SDoc+pprFormat :: IsLine doc => Format -> doc pprFormat x = case x of   II8   -> text "b"   II16  -> text "w"@@ -406,14 +408,14 @@   FF32  -> text "ss"      -- "scalar single-precision float" (SSE2)   FF64  -> text "sd"      -- "scalar double-precision float" (SSE2) -pprFormat_x87 :: Format -> SDoc+pprFormat_x87 :: IsLine doc => Format -> doc pprFormat_x87 x = case x of   FF32  -> text "s"   FF64  -> text "l"   _     -> panic "X86.Ppr.pprFormat_x87"  -pprCond :: Cond -> SDoc+pprCond :: IsLine doc => Cond -> doc pprCond c = case c of {   GEU     -> text "ae";   LU   -> text "b";   EQQ     -> text "e";    GTT  -> text "g";@@ -426,13 +428,13 @@   ALWAYS  -> text "mp"}  -pprImm :: Platform -> Imm -> SDoc+pprImm :: IsLine doc => Platform -> Imm -> doc pprImm platform = \case    ImmInt i            -> int i    ImmInteger i        -> integer i    ImmCLbl l           -> pprAsmLabel platform l    ImmIndex l i        -> pprAsmLabel platform l <> char '+' <> int i-   ImmLit s            -> text s+   ImmLit s            -> ftext s    ImmFloat f          -> float $ fromRational f    ImmDouble d         -> double $ fromRational d    ImmConstantSum a b  -> pprImm platform a <> char '+' <> pprImm platform b@@ -440,7 +442,7 @@   -pprAddr :: Platform -> AddrMode -> SDoc+pprAddr :: IsLine doc => Platform -> AddrMode -> doc pprAddr platform (ImmAddr imm off)   = let pp_imm = pprImm platform imm     in@@ -471,16 +473,16 @@     ppr_disp imm        = pprImm platform imm  -- | Print section header and appropriate alignment for that section.-pprSectionAlign :: NCGConfig -> Section -> SDoc+pprSectionAlign :: IsDoc doc => NCGConfig -> Section -> doc pprSectionAlign _config (Section (OtherSection _) _) =      panic "X86.Ppr.pprSectionAlign: unknown section" pprSectionAlign config sec@(Section seg _) =-    pprSectionHeader config sec $$+    line (pprSectionHeader config sec) $$     pprAlignForSection (ncgPlatform config) seg  -- | Print appropriate alignment for the given section type.-pprAlignForSection :: Platform -> SectionType -> SDoc-pprAlignForSection platform seg =+pprAlignForSection :: IsDoc doc => Platform -> SectionType -> doc+pprAlignForSection platform seg = line $     text ".align " <>     case platformOS platform of       -- Darwin: alignments are given as shifts.@@ -505,9 +507,9 @@            CString           -> int 1            _                 -> int 8 -pprDataItem :: NCGConfig -> CmmLit -> SDoc+pprDataItem :: IsDoc doc => NCGConfig -> CmmLit -> doc pprDataItem config lit-  = vcat (ppr_item (cmmTypeFormat $ cmmLitType platform lit) lit)+  = lines_ (ppr_item (cmmTypeFormat $ cmmLitType platform lit) lit)     where         platform = ncgPlatform config         imm = litToImm lit@@ -535,26 +537,26 @@               _ -> [text "\t.quad\t" <> pprImm platform imm]  -asmComment :: SDoc -> SDoc+asmComment :: IsLine doc => doc -> doc asmComment c = whenPprDebug $ text "# " <> c -pprInstr :: Platform -> Instr -> SDoc+pprInstr :: forall doc. IsDoc doc => Platform -> Instr -> doc pprInstr platform i = case i of    COMMENT s-      -> asmComment s+      -> line (asmComment (ftext s)) -   LOCATION file line col _name-      -> text "\t.loc " <> ppr file <+> ppr line <+> ppr col+   LOCATION file line' col _name+      -> line (text "\t.loc " <> int file <+> int line' <+> int col)     DELTA d-      -> asmComment $ text ("\tdelta = " ++ show d)+      -> line (asmComment $ text ("\tdelta = " ++ show d))     NEWBLOCK _       -> panic "pprInstr: NEWBLOCK"     UNWIND lbl d-      -> asmComment (text "\tunwind = " <> pdoc platform d)-         $$ pprAsmLabel platform lbl <> colon+      -> line (asmComment (text "\tunwind = " <> pprUnwindTable platform d))+         $$ line (pprAsmLabel platform lbl <> colon)     LDATA _ _       -> panic "pprInstr: LDATA"@@ -772,19 +774,19 @@ -- POPA  -> text "\tpopal"     NOP-      -> text "\tnop"+      -> line $ text "\tnop"     CLTD II8-      -> text "\tcbtw"+      -> line $ text "\tcbtw"     CLTD II16-      -> text "\tcwtd"+      -> line $ text "\tcwtd"     CLTD II32-      -> text "\tcltd"+      -> line $ text "\tcltd"     CLTD II64-      -> text "\tcqto"+      -> line $ text "\tcqto"     CLTD x       -> panic $ "pprInstr: CLTD " ++ show x@@ -803,19 +805,19 @@       -> pprCondInstr (text "j") cond (pprImm platform imm)     JMP (OpImm imm) _-      -> text "\tjmp " <> pprImm platform imm+      -> line $ text "\tjmp " <> pprImm platform imm     JMP op _-      -> text "\tjmp *" <> pprOperand platform (archWordFormat (target32Bit platform)) op+      -> line $ text "\tjmp *" <> pprOperand platform (archWordFormat (target32Bit platform)) op     JMP_TBL op _ _ _       -> pprInstr platform (JMP op [])     CALL (Left imm) _-      -> text "\tcall " <> pprImm platform imm+      -> line $ text "\tcall " <> pprImm platform imm     CALL (Right reg) _-      -> text "\tcall *" <> pprReg platform (archWordFormat (target32Bit platform)) reg+      -> line $ text "\tcall *" <> pprReg platform (archWordFormat (target32Bit platform)) reg     IDIV fmt op       -> pprFormatOp (text "idiv") fmt op@@ -859,20 +861,20 @@         -- FETCHGOT for PIC on ELF platforms    FETCHGOT reg-      -> vcat [ text "\tcall 1f",-                hcat [ text "1:\tpopl\t", pprReg platform II32 reg ],-                hcat [ text "\taddl\t$_GLOBAL_OFFSET_TABLE_+(.-1b), ",-                       pprReg platform II32 reg ]-              ]+      -> lines_ [ text "\tcall 1f",+                  hcat [ text "1:\tpopl\t", pprReg platform II32 reg ],+                  hcat [ text "\taddl\t$_GLOBAL_OFFSET_TABLE_+(.-1b), ",+                         pprReg platform II32 reg ]+                ]      -- FETCHPC for PIC on Darwin/x86     -- get the instruction pointer into a register     -- (Terminology note: the IP is called Program Counter on PPC,     --  and it's a good thing to use the same name on both platforms)    FETCHPC reg-      -> vcat [ text "\tcall 1f",-                hcat [ text "1:\tpopl\t", pprReg platform II32 reg ]-              ]+      -> lines_ [ text "\tcall 1f",+                  hcat [ text "1:\tpopl\t", pprReg platform II32 reg ]+                ]     -- the    -- GST fmt src addr ==> FLD dst ; FSTPsz addr@@ -881,10 +883,10 @@     -- Atomics    LOCK i-      -> text "\tlock" $$ pprInstr platform i+      -> line (text "\tlock") $$ pprInstr platform i     MFENCE-      -> text "\tmfence"+      -> line $ text "\tmfence"     XADD format src dst       -> pprFormatOpOp (text "xadd") format src dst@@ -894,46 +896,46 @@     where-   gtab :: SDoc+   gtab :: Line doc    gtab  = char '\t' -   gsp :: SDoc+   gsp :: Line doc    gsp   = char ' '   -   pprX87 :: Instr -> SDoc -> SDoc+   pprX87 :: Instr -> Line doc -> doc    pprX87 fake actual-      = (char '#' <> pprX87Instr fake) $$ actual+      = line (char '#' <> pprX87Instr fake) $$ line actual -   pprX87Instr :: Instr -> SDoc+   pprX87Instr :: Instr -> Line doc    pprX87Instr (X87Store fmt dst) = pprFormatAddr (text "gst") fmt dst    pprX87Instr _ = panic "X86.Ppr.pprX87Instr: no match" -   pprDollImm :: Imm -> SDoc+   pprDollImm :: Imm -> Line doc    pprDollImm i = text "$" <> pprImm platform i  -   pprOperand :: Platform -> Format -> Operand -> SDoc+   pprOperand :: Platform -> Format -> Operand -> Line doc    pprOperand platform f op = case op of       OpReg r   -> pprReg platform f r       OpImm i   -> pprDollImm i       OpAddr ea -> pprAddr platform ea  -   pprMnemonic_  :: SDoc -> SDoc+   pprMnemonic_  :: Line doc -> Line doc    pprMnemonic_ name =       char '\t' <> name <> space  -   pprMnemonic  :: SDoc -> Format -> SDoc+   pprMnemonic  :: Line doc -> Format -> Line doc    pprMnemonic name format =       char '\t' <> name <> pprFormat format <> space  -   pprFormatImmOp :: SDoc -> Format -> Imm -> Operand -> SDoc+   pprFormatImmOp :: Line doc -> Format -> Imm -> Operand -> doc    pprFormatImmOp name format imm op1-     = hcat [+     = line $ hcat [            pprMnemonic name format,            char '$',            pprImm platform imm,@@ -942,24 +944,24 @@        ]  -   pprFormatOp_ :: SDoc -> Format -> Operand -> SDoc+   pprFormatOp_ :: Line doc -> Format -> Operand -> doc    pprFormatOp_ name format op1-     = hcat [+     = line $ hcat [            pprMnemonic_ name ,            pprOperand platform format op1        ] -   pprFormatOp :: SDoc -> Format -> Operand -> SDoc+   pprFormatOp :: Line doc -> Format -> Operand -> doc    pprFormatOp name format op1-     = hcat [+     = line $ hcat [            pprMnemonic name format,            pprOperand platform format op1        ]  -   pprFormatOpOp :: SDoc -> Format -> Operand -> Operand -> SDoc+   pprFormatOpOp :: Line doc -> Format -> Operand -> Operand -> doc    pprFormatOpOp name format op1 op2-     = hcat [+     = line $ hcat [            pprMnemonic name format,            pprOperand platform format op1,            comma,@@ -967,18 +969,18 @@        ]  -   pprOpOp :: SDoc -> Format -> Operand -> Operand -> SDoc+   pprOpOp :: Line doc -> Format -> Operand -> Operand -> doc    pprOpOp name format op1 op2-     = hcat [+     = line $ hcat [            pprMnemonic_ name,            pprOperand platform format op1,            comma,            pprOperand platform format op2        ] -   pprRegReg :: SDoc -> Reg -> Reg -> SDoc+   pprRegReg :: Line doc -> Reg -> Reg -> doc    pprRegReg name reg1 reg2-     = hcat [+     = line $ hcat [            pprMnemonic_ name,            pprReg platform (archWordFormat (target32Bit platform)) reg1,            comma,@@ -986,18 +988,18 @@        ]  -   pprFormatOpReg :: SDoc -> Format -> Operand -> Reg -> SDoc+   pprFormatOpReg :: Line doc -> Format -> Operand -> Reg -> doc    pprFormatOpReg name format op1 reg2-     = hcat [+     = line $ hcat [            pprMnemonic name format,            pprOperand platform format op1,            comma,            pprReg platform (archWordFormat (target32Bit platform)) reg2        ] -   pprCondOpReg :: SDoc -> Format -> Cond -> Operand -> Reg -> SDoc+   pprCondOpReg :: Line doc -> Format -> Cond -> Operand -> Reg -> doc    pprCondOpReg name format cond op1 reg2-     = hcat [+     = line $ hcat [            char '\t',            name,            pprCond cond,@@ -1007,18 +1009,18 @@            pprReg platform format reg2        ] -   pprFormatFormatOpReg :: SDoc -> Format -> Format -> Operand -> Reg -> SDoc+   pprFormatFormatOpReg :: Line doc -> Format -> Format -> Operand -> Reg -> doc    pprFormatFormatOpReg name format1 format2 op1 reg2-     = hcat [+     = line $ hcat [            pprMnemonic name format2,            pprOperand platform format1 op1,            comma,            pprReg platform format2 reg2        ] -   pprFormatOpOpReg :: SDoc -> Format -> Operand -> Operand -> Reg -> SDoc+   pprFormatOpOpReg :: Line doc -> Format -> Operand -> Operand -> Reg -> doc    pprFormatOpOpReg name format op1 op2 reg3-     = hcat [+     = line $ hcat [            pprMnemonic name format,            pprOperand platform format op1,            comma,@@ -1029,7 +1031,7 @@   -   pprFormatAddr :: SDoc -> Format -> AddrMode -> SDoc+   pprFormatAddr :: Line doc -> Format -> AddrMode -> Line doc    pprFormatAddr name format  op      = hcat [            pprMnemonic name format,@@ -1037,9 +1039,9 @@            pprAddr platform op        ] -   pprShift :: SDoc -> Format -> Operand -> Operand -> SDoc+   pprShift :: Line doc -> Format -> Operand -> Operand -> doc    pprShift name format src dest-     = hcat [+     = line $ hcat [            pprMnemonic name format,            pprOperand platform II8 src,  -- src is 8-bit sized            comma,@@ -1047,15 +1049,15 @@        ]  -   pprFormatOpOpCoerce :: SDoc -> Format -> Format -> Operand -> Operand -> SDoc+   pprFormatOpOpCoerce :: Line doc -> Format -> Format -> Operand -> Operand -> doc    pprFormatOpOpCoerce name format1 format2 op1 op2-     = hcat [ char '\t', name, pprFormat format1, pprFormat format2, space,+     = line $ hcat [ char '\t', name, pprFormat format1, pprFormat format2, space,            pprOperand platform format1 op1,            comma,            pprOperand platform format2 op2        ]  -   pprCondInstr :: SDoc -> Cond -> SDoc -> SDoc+   pprCondInstr :: Line doc -> Cond -> Line doc -> doc    pprCondInstr name cond arg-     = hcat [ char '\t', name, pprCond cond, space, arg]+     = line $ hcat [ char '\t', name, pprCond cond, space, arg]
compiler/GHC/CmmToAsm/X86/Regs.hs view
@@ -48,6 +48,7 @@ where  import GHC.Prelude+import GHC.Data.FastString  import GHC.Platform.Regs import GHC.Platform.Reg@@ -110,14 +111,14 @@   = ImmInt      Int   | ImmInteger  Integer     -- Sigh.   | ImmCLbl     CLabel      -- AbstractC Label (with baggage)-  | ImmLit      String+  | ImmLit      FastString   | ImmIndex    CLabel Int   | ImmFloat    Rational   | ImmDouble   Rational   | ImmConstantSum Imm Imm   | ImmConstantDiff Imm Imm -strImmLit :: String -> Imm+strImmLit :: FastString -> Imm strImmLit s = ImmLit s  
compiler/GHC/CmmToC.hs view
@@ -53,7 +53,6 @@ import GHC.Utils.Panic import GHC.Utils.Monad.State.Strict (State (..), runState, state) import GHC.Utils.Misc-import GHC.Utils.Trace  import Data.ByteString (ByteString) import qualified Data.ByteString as BS@@ -431,8 +430,7 @@ pprMachOpApp platform op args   | isMulMayOfloOp op   = text "mulIntMayOflo" <> parens (commafy (map (pprExpr platform) args))-  where isMulMayOfloOp (MO_U_MulMayOflo _) = True-        isMulMayOfloOp (MO_S_MulMayOflo _) = True+  where isMulMayOfloOp (MO_S_MulMayOflo _) = True         isMulMayOfloOp _ = False  pprMachOpApp platform mop args@@ -775,10 +773,6 @@         MO_S_MulMayOflo _ -> pprTrace "offending mop:"                                 (text "MO_S_MulMayOflo")                                 (panic $ "PprC.pprMachOp_for_C: MO_S_MulMayOflo"-                                      ++ " should have been handled earlier!")-        MO_U_MulMayOflo _ -> pprTrace "offending mop:"-                                (text "MO_U_MulMayOflo")-                                (panic $ "PprC.pprMachOp_for_C: MO_U_MulMayOflo"                                       ++ " should have been handled earlier!")          MO_V_Insert {}    -> pprTrace "offending mop:"
compiler/GHC/CmmToLlvm.hs view
@@ -110,8 +110,8 @@     header =       let target  = llvmCgLlvmTarget cfg           llvmCfg = llvmCgLlvmConfig cfg-      in     text ("target datalayout = \"" ++ getDataLayout llvmCfg target ++ "\"")-         $+$ text ("target triple = \"" ++ target ++ "\"")+      in     (text "target datalayout = \"" <> text (getDataLayout llvmCfg target) <> text "\"")+         $+$ (text "target triple = \"" <> text target <> text "\"")      getDataLayout :: LlvmConfig -> String -> String     getDataLayout config target =
compiler/GHC/CmmToLlvm/CodeGen.hs view
@@ -1451,7 +1451,6 @@     MO_S_MulMayOflo _ -> panicOp     MO_S_Quot _       -> panicOp     MO_S_Rem _        -> panicOp-    MO_U_MulMayOflo _ -> panicOp     MO_U_Quot _       -> panicOp     MO_U_Rem _        -> panicOp @@ -1632,8 +1631,6 @@     MO_Add _ -> genBinMach LM_MO_Add     MO_Sub _ -> genBinMach LM_MO_Sub     MO_Mul _ -> genBinMach LM_MO_Mul--    MO_U_MulMayOflo _ -> panic "genMachOp: MO_U_MulMayOflo unsupported!"      MO_S_MulMayOflo w -> isSMulOK w x y 
compiler/GHC/Core/Opt/CSE.hs view
@@ -4,11 +4,6 @@ \section{Common subexpression} -} ---{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}-{-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}- module GHC.Core.Opt.CSE (cseProgram, cseOneExpr) where  import GHC.Prelude@@ -32,6 +27,7 @@ import GHC.Core.Map.Expr import GHC.Utils.Misc   ( filterOut, equalLength ) import GHC.Utils.Panic+import Data.Functor.Identity ( Identity (..) ) import Data.List        ( mapAccumL )  {-@@ -412,7 +408,7 @@   = (extendCSRecEnv env1 out_id rhs'' id_expr', Rec [(zapped_id, rhs')])    where-    (env1, [out_id]) = addRecBinders env [in_id]+    (env1, Identity out_id) = addRecBinders env (Identity in_id)     rhs'  = cseExpr env1 rhs     rhs'' = stripTicksE tickishFloatable rhs'     ticks = stripTicksT tickishFloatable rhs'@@ -916,7 +912,8 @@                 where                   (sub', vs') = substBndrs (cs_subst cse) vs -addRecBinders :: CSEnv -> [Id] -> (CSEnv, [Id])-addRecBinders cse vs = (cse { cs_subst = sub' }, vs')-                where-                  (sub', vs') = substRecBndrs (cs_subst cse) vs+addRecBinders :: Traversable f => CSEnv -> f Id -> (CSEnv, f Id)+addRecBinders = \ cse vs ->+    let (sub', vs') = substRecBndrs (cs_subst cse) vs+    in (cse { cs_subst = sub' }, vs')+{-# INLINE addRecBinders #-}
compiler/GHC/Core/Opt/CallArity.hs view
@@ -728,7 +728,7 @@ resDel v (!g, !ae) = (g `delNode` v, ae `delVarEnv` v)  domRes :: CallArityRes -> UnVarSet-domRes (_, ae) = varEnvDom ae+domRes (_, ae) = varEnvDomain ae  -- In the result, find out the minimum arity and whether the variable is called -- at most once.
compiler/GHC/Core/Opt/DmdAnal.hs view
@@ -34,7 +34,8 @@ import GHC.Core.Predicate( isClassPred ) import GHC.Core.FVs      ( rulesRhsFreeIds, bndrRuleAndUnfoldingIds ) import GHC.Core.Coercion ( Coercion )-import GHC.Core.TyCo.FVs ( coVarsOfCos )+import GHC.Core.TyCo.FVs     ( coVarsOfCos )+import GHC.Core.TyCo.Compare ( eqType ) import GHC.Core.FamInstEnv import GHC.Core.Opt.Arity ( typeArity ) import GHC.Utils.Misc@@ -45,9 +46,8 @@ import GHC.Builtin.Types.Prim ( realWorldStatePrimTy ) import GHC.Types.Unique.Set import GHC.Types.Unique.MemoFun+import GHC.Types.RepType -import GHC.Utils.Trace-_ = pprTrace -- Tired of commenting out the import all the time  {- ************************************************************************@@ -982,9 +982,9 @@ -- See Note [What are demand signatures?] in "GHC.Types.Demand" dmdTransform env var sd   -- Data constructors-  | isDataConWorkId var-  = -- pprTraceWith "dmdTransform:DataCon" (\ty -> ppr var $$ ppr sd $$ ppr ty) $-    dmdTransformDataConSig (idArity var) sd+  | Just con <- isDataConWorkId_maybe var+  = -- pprTraceWith "dmdTransform:DataCon" (\ty -> ppr con $$ ppr sd $$ ppr ty) $+    dmdTransformDataConSig (dataConRepStrictness con) sd   -- See Note [DmdAnal for DataCon wrappers]   | isDataConWrapId var, let rhs = uf_tmpl (realIdUnfolding var)   , WithDmdType dmd_ty _rhs' <- dmdAnal env sd rhs@@ -1113,7 +1113,7 @@ resultType_maybe :: Id -> Maybe Type resultType_maybe id   | (pis,ret_ty) <- splitPiTys (idType id)-  , count (not . isNamedBinder) pis == idArity id+  , count isAnonPiTyBinder pis == idArity id   = Just $! ret_ty   | otherwise   = Nothing@@ -1522,6 +1522,9 @@       ... ``` This is currently a bug that we willingly accept and it's documented in #21128.++See also Note [indexError] in base:GHC.Ix, which describes how we use+SPECIALISE to mitigate this problem for indexError. -}  {- *********************************************************************@@ -1764,7 +1767,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In 'finaliseArgBoxities' we don't want to generate workers with zillions of argument when, say given a strict record with zillions of fields.  So we-limit the maximum number of worker args to the maximum of+limit the maximum number of worker args ('max_wkr_args') to the maximum of   - -fmax-worker-args=N   - The number of args in the original function; if it already has has     zillions of arguments we don't want to seek /fewer/ args in the worker.@@ -1773,11 +1776,92 @@ We pursue a "layered" strategy for unboxing: we unbox the top level of the argument(s), subject to budget; if there are any arguments left we unbox the next layer, using that depleted budget.+Unboxing an argument *increases* the budget for the inner layer roughly+according to how many registers that argument takes (unboxed tuples take+multiple registers, see below), as determined by 'unariseArity'.+Budget is spent when we have to pass a non-absent field as a parameter.  To achieve this, we use the classic almost-circular programming technique in which we we write one pass that takes a lazy list of the Budgets for every-layer.+layer. The effect is that of a breadth-first search (over argument type and+demand structure) to compute Budgets followed by a depth-first search to+construct the product demands, but laziness allows us to do it all in one+pass and without intermediate data structures. +Suppose we have -fmax-worker-args=4 for the remainder of this Note.+Then consider this example function:++  boxed :: (Int, Int) -> (Int, (Int, Int, Int)) -> Int+  boxed (a,b) (c, (d,e,f)) = a + b + c + d + e + f++With a budget of 4 args to spend (number of args is only 2), we'd be served well+to unbox both pairs, but not the triple. Indeed, that is what the algorithm+computes, and the following pictogram shows how the budget layers are computed.+Each layer is started with `n ~>`, where `n` is the budget at the start of the+layer. We write -n~> when we spend budget (and n is the remaining budget) and++n~> when we earn budget. We separate unboxed args with ][ and indicate+inner budget threads becoming negative in braces {{}}, so that we see which+unboxing decision we do *not* commit to. Without further ado:++  4 ~> ][     (a,b) -3~>               ][     (c, ...) -2~>+       ][      | |                     ][      |   |+       ][      | +-------------+       ][      |   +-----------------++       ][      |               |       ][      |                     |+       ][      v               v       ][      v                     v+  2 ~> ][ +3~> a  -2~> ][      b  -1~> ][ +2~> c  -1~> ][        (d, e, f) -0~>+       ][      |       ][      |       ][      |       ][ {{      |  |  |                          }}+       ][      |       ][      |       ][      |       ][ {{      |  |  +----------------+         }}+       ][      v       ][      v       ][      v       ][ {{      v  +------v            v         }}+  0 ~> ][ +1~> I# -0~> ][ +1~> I# -0~> ][ +1~> I# -0~> ][ {{ +1~> d -0~> ][ e -(-1)~> ][ f -(-2)~> }}++Unboxing increments the budget we have on the next layer (because we don't need+to retain the boxed arg), but in turn the inner layer must afford to retain all+non-absent fields, each decrementing the budget. Note how the budget becomes+negative when trying to unbox the triple and the unboxing decision is "rolled+back". This is done by the 'positiveTopBudget' guard.++There's a bit of complication as a result of handling unboxed tuples correctly;+specifically, handling nested unboxed tuples. Consider (#21737)++  unboxed :: (Int, Int) -> (# Int, (# Int, Int, Int #) #) -> Int+  unboxed (a,b) (# c, (# d, e, f #) #) = a + b + c + d + e + f++Recall that unboxed tuples will be flattened to individual arguments during+unarisation. Here, `unboxed` will have 5 arguments at runtime because of the+nested unboxed tuple, which will be flattened to 4 args. So it's best to leave+`(a,b)` boxed (because we already are above our arg threshold), but unbox `c`+through `f` because that doesn't increase the number of args post unarisation.++Note that the challenge is that syntactically, `(# d, e, f #)` occurs in a+deeper layer than `(a, b)`. Treating unboxed tuples as a regular data type, we'd+make the same unboxing decisions as for `boxed` above; although our starting+budget is 5 (Here, the number of args is greater than -fmax-worker-args), it's+not enough to unbox the triple (we'd finish with budget -1). So we'd unbox `a`+through `c`, but not `d` through `f`, which is silly, because then we'd end up+having 6 arguments at runtime, of which `d` through `f` weren't unboxed.++Hence we pretend that the fields of unboxed tuples appear in the same budget+layer as the tuple itself. For example at the top-level, `(# x,y #)` is to be+treated just like two arguments `x` and `y`.+Of course, for that to work, our budget calculations must initialise+'max_wkr_args' to 5, based on the 'unariseArity' of each Core arg: That would be+1 for the pair and 4 for the unboxed pair. Then when we decide whether to unbox+the unboxed pair, we *directly* recurse into the fields, spending our budget+on retaining `c` and (after recursing once more) `d` through `f` as arguments,+depleting our budget completely in the first layer. Pictorially:++  5 ~> ][         (a,b) -4~>             ][         (# c, ... #)+       ][ {{      | |                 }} ][      c  -3~> ][ (# d, e, f #)+       ][ {{      | +-------+         }} ][      |       ][      d  -2~> ][      e  -1~> ][      f  -0~>+       ][ {{      |         |         }} ][      |       ][      |       ][      |       ][      |+       ][ {{      v         v         }} ][      v       ][      v       ][      v       ][      v+  0 ~> ][ {{ +1~> a -0~> ][ b -(-1)~> }} ][ +1~> I# -0~> ][ +1~> I# -0~> ][ +1~> I# -0~> ][ +1~> I# -0~>++As you can see, we have no budget left to justify unboxing `(a,b)` on the second+layer, which is good, because it would increase the number of args. Also note+that we can still unbox `c` through `f` in this layer, because doing so has a+net zero effect on budget.+ Note [The OPAQUE pragma and avoiding the reboxing of arguments] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In https://gitlab.haskell.org/ghc/ghc/-/issues/13143 it was identified that when@@ -1797,11 +1881,18 @@ along in boxed form and as such dissuade the creation of reboxing workers. -} -data Budgets = MkB Arity Budgets   -- An infinite list of arity budgets+-- | How many registers does this type take after unarisation?+unariseArity :: Type -> Arity+unariseArity ty = length (typePrimRep ty) -incTopBudget :: Budgets -> Budgets-incTopBudget (MkB n bg) = MkB (n+1) bg+data Budgets = MkB !Arity Budgets   -- An infinite list of arity budgets +earnTopBudget :: Budgets -> Budgets+earnTopBudget (MkB n bg) = MkB (n+1) bg++spendTopBudget :: Arity -> Budgets -> Budgets+spendTopBudget m (MkB n bg) = MkB (n-m) bg+ positiveTopBudget :: Budgets -> Bool positiveTopBudget (MkB n _) = n >= 0 @@ -1813,7 +1904,8 @@              -- Then there are no binders; we don't worker/wrapper; and we              -- simply want to give f the same demand signature as g -  | otherwise+  | otherwise -- NB: arity is the threshold_arity, which might be less than+              -- manifest arity for join points   = -- pprTrace "finaliseArgBoxities" (     --   vcat [text "function:" <+> ppr fn     --        , text "dmds before:" <+> ppr (map idDemandInfo (filter isId bndrs))@@ -1825,8 +1917,10 @@   where     opts            = ae_opts env     (bndrs, _body)  = collectBinders rhs-    max_wkr_args    = dmd_max_worker_args opts `max` arity-                      -- See Note [Worker argument budget]+    unarise_arity   = sum [ unariseArity (idType b) | b <- bndrs, isId b ]+    max_wkr_args    = dmd_max_worker_args opts `max` unarise_arity+                      -- This is the budget initialisation step of+                      -- Note [Worker argument budget]      -- This is the key line, which uses almost-circular programming     -- The remaining budget from one layer becomes the initial@@ -1870,22 +1964,49 @@       = case wantToUnboxArg env ty str_mark dmd of           DropAbsent -> (bg, dmd) -          DontUnbox | is_bot_fn, isTyVarTy ty -> (decremented_bg, dmd)-                    | otherwise               -> (decremented_bg, trimBoxity dmd)+          DontUnbox | is_bot_fn, isTyVarTy ty -> (retain_budget, dmd)+                    | otherwise               -> (retain_budget, trimBoxity dmd)             -- If bot: Keep deep boxity even though WW won't unbox             -- See Note [Boxity for bottoming functions] case (A)             -- trimBoxity: see Note [No lazy, Unboxed demands in demand signature]+            where+              retain_budget = spendTopBudget (unariseArity ty) bg+                -- spendTopBudget: spend from our budget the cost of the+                -- retaining the arg+                -- The unboxed case does happen here, for example+                --   app g x = g x :: (# Int, Int #)+                -- here, `x` is used `L`azy and thus Boxed -          DoUnbox triples -> (MkB (bg_top-1) final_bg_inner, final_dmd)+          DoUnbox triples+            | isUnboxedTupleType ty+            , (bg', dmds') <- go_args bg triples+            -> (bg', n :* (mkProd Unboxed $! dmds'))+                     -- See Note [Worker argument budget]+                     -- unboxed tuples are always unboxed, deeply+                     -- NB: Recurse with bg, *not* bg_inner! The unboxed fields+                     -- are at the same budget layer.++            | isUnboxedSumType ty+            -> pprPanic "Unboxing through unboxed sum" (ppr fn <+> ppr ty)+                     -- We currently don't return DoUnbox for unboxed sums.+                     -- But hopefully we will at some point. When that happens,+                     -- it would still be impossible to predict the effect+                     -- of dropping absent fields and unboxing others on the+                     -- unariseArity of the sum without losing sanity.+                     -- We could overwrite bg_top with the one from+                     -- retain_budget while still unboxing inside the alts as in+                     -- the tuple case for a conservative solution, though.++            | otherwise+            -> (spendTopBudget 1 (MkB bg_top final_bg_inner), final_dmd)             where-              (bg_inner', dmds') = go_args (incTopBudget bg_inner) triples-                     -- incTopBudget: give one back for the arg we are unboxing+              (bg_inner', dmds') = go_args (earnTopBudget bg_inner) triples+                     -- earnTopBudget: give back the cost of retaining the+                     -- arg we are insted unboxing.               dmd' = n :* (mkProd Unboxed $! dmds')-              (final_bg_inner, final_dmd)+              ~(final_bg_inner, final_dmd) -- "~": This match *must* be lazy!                  | positiveTopBudget bg_inner' = (bg_inner', dmd')                  | otherwise                   = (bg_inner,  trimBoxity dmd)-      where-        decremented_bg = MkB (bg_top-1) bg_inner      add_demands :: [Demand] -> CoreExpr -> CoreExpr     -- Attach the demands to the outer lambdas of this expression
compiler/GHC/Core/Opt/Exitify.hs view
@@ -265,7 +265,7 @@                          `extendInScopeSet` exit_id_tmpl -- just cosmetics     return (uniqAway avoid exit_id_tmpl)   where-    exit_id_tmpl = mkSysLocal (fsLit "exit") initExitJoinUnique Many ty+    exit_id_tmpl = mkSysLocal (fsLit "exit") initExitJoinUnique ManyTy ty                     `asJoinId` join_arity  addExit :: InScopeSet -> JoinArity -> CoreExpr -> ExitifyM JoinId
compiler/GHC/Core/Opt/Pipeline.hs view
@@ -22,7 +22,7 @@  import GHC.Core import GHC.Core.Opt.CSE  ( cseProgram )-import GHC.Core.Rules   ( mkRuleBase, ruleCheckProgram, getRules )+import GHC.Core.Rules   ( RuleBase, mkRuleBase, ruleCheckProgram, getRules ) import GHC.Core.Ppr     ( pprCoreBindings ) import GHC.Core.Utils   ( dumpIdInfoOfProgram ) import GHC.Core.Lint    ( lintAnnots )@@ -53,9 +53,7 @@ import GHC.Utils.Outputable import GHC.Utils.Panic -import GHC.Unit.Module.Env import GHC.Unit.Module.ModGuts-import GHC.Unit.Module.Deps  import GHC.Types.Id.Info import GHC.Types.Basic@@ -78,14 +76,12 @@ core2core :: HscEnv -> ModGuts -> IO ModGuts core2core hsc_env guts@(ModGuts { mg_module  = mod                                 , mg_loc     = loc-                                , mg_deps    = deps                                 , mg_rdr_env = rdr_env })   = do { let builtin_passes = getCoreToDo dflags hpt_rule_base extra_vars-             orph_mods = mkModuleSet (mod : dep_orphs deps)              uniq_mask = 's'-       ;+        ; (guts2, stats) <- runCoreM hsc_env hpt_rule_base uniq_mask mod-                                    orph_mods print_unqual loc $+                                    name_ppr_ctx loc $                            do { hsc_env' <- getHscEnv                               ; all_passes <- withPlugins (hsc_plugins hsc_env')                                                 installCoreToDos@@ -105,7 +101,8 @@     home_pkg_rules = hptRules hsc_env (moduleUnitId mod) (GWIB { gwib_mod = moduleName mod                                                                , gwib_isBoot = NotBoot })     hpt_rule_base  = mkRuleBase home_pkg_rules-    print_unqual   = mkPrintUnqualified (hsc_unit_env hsc_env) rdr_env+    name_ppr_ctx   = mkNamePprCtx ptc (hsc_unit_env hsc_env) rdr_env+    ptc            = initPromotionTickContext dflags     -- mod: get the module out of the current HscEnv so we can retrieve it from the monad.     -- This is very convienent for the users of the monad (e.g. plugins do not have to     -- consume the ModGuts to find the module) but somewhat ugly because mg_module may@@ -121,7 +118,8 @@ -}  getCoreToDo :: DynFlags -> RuleBase -> [Var] -> [CoreToDo]-getCoreToDo dflags rule_base extra_vars+-- This function builds the pipeline of optimisations+getCoreToDo dflags hpt_rule_base extra_vars   = flatten_todos core_todo   where     phases        = simplPhases        dflags@@ -176,7 +174,7 @@      ----------------------------     run_simplifier mode iter-      = CoreDoSimplify $ initSimplifyOpts dflags extra_vars iter mode rule_base+      = CoreDoSimplify $ initSimplifyOpts dflags extra_vars iter mode hpt_rule_base      simpl_phase phase name iter = CoreDoPasses $                                   [ maybe_strictness_before phase@@ -491,10 +489,15 @@   let fam_envs = (p_fam_env, mg_fam_inst_env guts)   let updateBinds  f = return $ guts { mg_binds = f (mg_binds guts) }   let updateBindsM f = f (mg_binds guts) >>= \b' -> return $ guts { mg_binds = b' }+  let name_ppr_ctx =+        mkNamePprCtx+          (initPromotionTickContext dflags)+          (hsc_unit_env hsc_env)+          (mg_rdr_env guts)    case pass of     CoreDoSimplify opts       -> {-# SCC "Simplify" #-}-                                 liftIOWithCount $ simplifyPgm logger (hsc_unit_env hsc_env) opts guts+                                 liftIOWithCount $ simplifyPgm logger (hsc_unit_env hsc_env) name_ppr_ctx opts guts      CoreCSE                   -> {-# SCC "CommonSubExpr" #-}                                  updateBinds cseProgram@@ -573,11 +576,9 @@     logger <- getLogger     withTiming logger (text "RuleCheck"<+>brackets (ppr $ mg_module guts))                 (const ()) $ do-        rb <- getRuleBase-        vis_orphs <- getVisibleOrphanMods-        let rule_fn fn = getRules (RuleEnv [rb] vis_orphs) fn-                          ++ (mg_rules guts)-        let ropts = initRuleOpts dflags+        rule_env <- initRuleEnv guts+        let rule_fn fn = getRules rule_env fn+            ropts = initRuleOpts dflags         liftIO $ logDumpMsg logger "Rule check"                      (ruleCheckProgram ropts current_phase pat                         rule_fn (mg_binds guts))
compiler/GHC/Core/Opt/SetLevels.hs view
@@ -77,12 +77,11 @@ import GHC.Core.FVs     -- all of it import GHC.Core.Subst import GHC.Core.Make    ( sortQuantVars )-import GHC.Core.Type    ( Type, splitTyConApp_maybe, tyCoVarsOfType+import GHC.Core.Type    ( Type, tyCoVarsOfType                         , mightBeUnliftedType, closeOverKindsDSet                         , typeHasFixedRuntimeRep                         )-import GHC.Core.Multiplicity     ( pattern Many )-import GHC.Core.DataCon ( dataConOrigResTy )+import GHC.Core.Multiplicity     ( pattern ManyTy )  import GHC.Types.Id import GHC.Types.Id.Info@@ -112,7 +111,6 @@ import GHC.Utils.Outputable import GHC.Utils.Panic import GHC.Utils.Panic.Plain-import GHC.Utils.Trace  import Data.Maybe @@ -465,7 +463,7 @@   , exprIsHNF (deTagExpr scrut')  -- See Note [Check the output scrutinee for exprIsHNF]   , not (isTopLvl dest_lvl)       -- Can't have top-level cases   , not (floatTopLvlOnly env)     -- Can float anywhere-  , Many <- idMult case_bndr     -- See Note [Floating linear case]+  , ManyTy <- idMult case_bndr     -- See Note [Floating linear case]   =     -- Always float the case if possible         -- Unlike lets we don't insist that it escapes a value lambda     do { (env1, (case_bndr' : bs')) <- cloneCaseBndrs env dest_lvl (case_bndr : bs)@@ -662,21 +660,20 @@   | escapes_value_lam   , not expr_ok_for_spec -- Boxing/unboxing isn't worth it for cheap expressions                          -- See Note [Test cheapness with exprOkForSpeculation]-  , Just (tc, _) <- splitTyConApp_maybe expr_ty-  , Just dc <- boxingDataCon_maybe tc-  , let dc_res_ty = dataConOrigResTy dc  -- No free type variables-        [bx_bndr, ubx_bndr] = mkTemplateLocals [dc_res_ty, expr_ty]+  , BI_Box { bi_data_con = box_dc, bi_inst_con = boxing_expr+           , bi_boxed_type = box_ty } <- boxingDataCon expr_ty+  , let [bx_bndr, ubx_bndr] = mkTemplateLocals [box_ty, expr_ty]   = do { expr1 <- lvlExpr rhs_env ann_expr        ; let l1r       = incMinorLvlFrom rhs_env              float_rhs = mkLams abs_vars_w_lvls $-                         Case expr1 (stayPut l1r ubx_bndr) dc_res_ty-                             [Alt DEFAULT [] (mkConApp dc [Var ubx_bndr])]+                         Case expr1 (stayPut l1r ubx_bndr) box_ty+                             [Alt DEFAULT [] (App boxing_expr (Var ubx_bndr))]         ; var <- newLvlVar float_rhs Nothing is_mk_static        ; let l1u      = incMinorLvlFrom env              use_expr = Case (mkVarApps (Var var) abs_vars)                              (stayPut l1u bx_bndr) expr_ty-                             [Alt (DataAlt dc) [stayPut l1u ubx_bndr] (Var ubx_bndr)]+                             [Alt (DataAlt box_dc) [stayPut l1u ubx_bndr] (Var ubx_bndr)]        ; return (Let (NonRec (TB var (FloatMe dest_lvl)) float_rhs)                      use_expr) } @@ -688,15 +685,16 @@     expr_ty      = exprType expr     fvs          = freeVarsOf ann_expr     fvs_ty       = tyCoVarsOfType expr_ty-    is_bot       = isBottomThunk mb_bot_str-    is_bot_lam   = isJust mb_bot_str+    is_bot_lam   = isJust mb_bot_str   -- True of bottoming thunks too!     is_function  = isFunction ann_expr     mb_bot_str   = exprBotStrictness_maybe expr                            -- See Note [Bottoming floats]                            -- esp Bottoming floats (2)     expr_ok_for_spec = exprOkForSpeculation expr-    dest_lvl     = destLevel env fvs fvs_ty is_function is_bot False-    abs_vars     = abstractVars dest_lvl env fvs+    abs_vars = abstractVars dest_lvl env fvs+    dest_lvl = destLevel env fvs fvs_ty is_function is_bot_lam False+               -- NB: is_bot_lam not is_bot; see (3) in+               --     Note [Bottoming floats]      -- float_is_new_lam: the floated thing will be a new value lambda     -- replacing, say (g (x+4)) by (lvl x).  No work is saved, nor is@@ -728,7 +726,9 @@     -- See Note [Floating to the top]     saves_alloc =  isTopLvl dest_lvl                 && floatConsts env-                && (not strict_ctxt || is_bot || exprIsHNF expr)+                && (   not strict_ctxt                     -- (a)+                    || exprIsHNF expr                      -- (b)+                    || (is_bot_lam && escapes_value_lam))  -- (c)  hasFreeJoin :: LevelEnv -> DVarSet -> Bool -- Has a free join point which is not being floated to top level.@@ -738,55 +738,63 @@ hasFreeJoin env fvs   = not (maxFvLevel isJoinId env fvs == tOP_LEVEL) -isBottomThunk :: Maybe (Arity, DmdSig, CprSig) -> Bool--- See Note [Bottoming floats] (2)-isBottomThunk (Just (0, _, _)) = True   -- Zero arity-isBottomThunk _                = False- {- Note [Floating to the top] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-We are keen to float something to the top level, even if it does not-escape a value lambda (and hence save work), for two reasons:+Suppose saves_work is False, i.e.+ - 'e' does not escape a value lambda (escapes_value_lam), or+ - 'e' would have added value lambdas if floated (float_is_new_lam)+Then we may still be keen to float a sub-expression 'e' to the top level,+for two reasons: -  * Doing so makes the function smaller, by floating out-    bottoming expressions, or integer or string literals.  That in-    turn makes it easier to inline, with less duplication.+ (i) Doing so makes the function smaller, by floating out+     bottoming expressions, or integer or string literals.  That in+     turn makes it easier to inline, with less duplication.+     This only matters if the floated sub-expression is inside a+     value-lambda, which in turn may be easier to inline. -  * (Minor) Doing so may turn a dynamic allocation (done by machine-    instructions) into a static one. Minor because we are assuming-    we are not escaping a value lambda.+ (ii) (Minor) Doing so may turn a dynamic allocation (done by machine+      instructions) into a static one. Minor because we are assuming+      we are not escaping a value lambda. -But do not do so if (saves_alloc):-     - the context is strict, and-     - the expression is not a HNF, and-     - the expression is not bottoming+But only do so if (saves_alloc):+     (a) the context is lazy (so we get allocation), or+     (b) the expression is a HNF (so we get allocation), or+     (c) the expression is bottoming and (i) applies+         (NB: if the expression is a lambda, (b) will apply;+              so this case only catches bottoming thunks)  Examples: -* Bottoming-      f x = case x of-              0 -> error <big thing>-              _ -> x+1-  Here we want to float (error <big thing>) to top level, abstracting-  over 'x', so as to make f's RHS smaller.--* HNF-      f = case y of-            True  -> p:q-            False -> blah-  We may as well float the (p:q) so it becomes a static data structure.--* Case scrutinee+* (a) Strict.  Case scrutinee       f = case g True of ....   Don't float (g True) to top level; then we have the admin of a   top-level thunk to worry about, with zero gain. -* Case alternative+* (a) Strict.  Case alternative       h = case y of              True  -> g True              False -> False   Don't float (g True) to the top level +* (b) HNF+      f = case y of+            True  -> p:q+            False -> blah+  We may as well float the (p:q) so it becomes a static data structure.++* (c) Bottoming expressions; see also Note [Bottoming floats]+      f x = case x of+              0 -> error <big thing>+              _ -> x+1+  Here we want to float (error <big thing>) to top level, abstracting+  over 'x', so as to make f's RHS smaller.++  But (#22494) if it's more like+       foo = case error <thing> of { ... }+  then there is no point in floating; we are never going to inline+  'foo' anyway.  So float bottoming things only if they escape+  a lambda.+ * Arguments      t = f (g True)   Prior to Apr 22 we didn't float (g True) to the top if f was strict.@@ -915,7 +923,7 @@ (1) We want to float a bottoming     expression even if it has free variables:         f = \x. g (let v = h x in error ("urk" ++ v))-    Then we'd like to abstract over 'x' can float the whole arg of g:+    Then we'd like to abstract over 'x', and float the whole arg of g:         lvl = \x. let v = h x in error ("urk" ++ v)         f = \x. g (lvl x)     To achieve this we pass is_bot to destLevel@@ -924,6 +932,12 @@     bottom.  Instead we treat the /body/ of such a function specially,     via point (1).  For example:         f = \x. ....(\y z. if x then error y else error z)....+    If we float the whole lambda thus+        lvl = \x. \y z. if x then error y else error z+        f = \x. ...(lvl x)...+    we may well end up eta-expanding that PAP to+        f = \x. ...(\y z. lvl x y z)...+     ===>         lvl = \x z y. if b then error y else error z         f = \x. ...(\y z. lvl x z y)...@@ -1405,7 +1419,7 @@           -> TyCoVarSet -- Free in the /type/ of the term                         -- (a subset of the previous argument)           -> Bool   -- True <=> is function-          -> Bool   -- True <=> is bottom+          -> Bool   -- True <=> looks like \x1..xn.bottom (n>=0)           -> Bool   -- True <=> is a join point           -> Level -- INVARIANT: if is_join=True then result >= join_ceiling@@ -1422,7 +1436,7 @@    | is_bot              -- Send bottoming bindings to the top   = as_far_as_poss      -- regardless; see Note [Bottoming floats]-                        -- Esp Bottoming floats (1)+                        -- Esp Bottoming floats (1) and (3)    | Just n_args <- floatLams env   , n_args > 0  -- n=0 case handled uniformly by the 'otherwise' case@@ -1732,7 +1746,7 @@       = mkExportedVanillaId (mkSystemVarName uniq (mkFastString "static_ptr"))                             rhs_ty       | otherwise-      = mkSysLocal (mkFastString "lvl") uniq Many rhs_ty+      = mkSysLocal (mkFastString "lvl") uniq ManyTy rhs_ty  -- | Clone the binders bound by a single-alternative case. cloneCaseBndrs :: LevelEnv -> Level -> [Var] -> LvlM (LevelEnv, [Var])
compiler/GHC/Core/Opt/SpecConstr.hs view
@@ -42,7 +42,7 @@ import GHC.Core.Rules import GHC.Core.Predicate ( typeDeterminesValue ) import GHC.Core.Type     hiding ( substTy )-import GHC.Core.TyCon   (TyCon, tyConUnique, tyConName )+import GHC.Core.TyCon   (TyCon, tyConName ) import GHC.Core.Multiplicity import GHC.Core.Ppr     ( pprParendExpr ) import GHC.Core.Make    ( mkImpossibleExpr )@@ -62,6 +62,7 @@ import GHC.Types.Cpr import GHC.Types.Unique.Supply import GHC.Types.Unique.FM+import GHC.Types.Unique( hasKey )  import GHC.Data.Maybe     ( orElse, catMaybes, isJust, isNothing ) import GHC.Data.Pair@@ -73,7 +74,6 @@ import GHC.Utils.Panic import GHC.Utils.Constants (debugIsOn) import GHC.Utils.Monad-import GHC.Utils.Trace  import GHC.Builtin.Names ( specTyConKey ) @@ -1137,14 +1137,13 @@  forceSpecArgTy :: ScEnv -> Type -> Bool forceSpecArgTy env ty-  | Just ty' <- coreView ty = forceSpecArgTy env ty'+  | isFunTy ty+  = False -forceSpecArgTy env ty   | Just (tycon, tys) <- splitTyConApp_maybe ty-  , tycon /= funTyCon-      = tyConUnique tycon == specTyConKey-        || lookupUFM (sc_annotations env) (tyConName tycon) == Just ForceSpecConstr-        || any (forceSpecArgTy env) tys+  = tycon `hasKey` specTyConKey+    || lookupUFM (sc_annotations env) (tyConName tycon) == Just ForceSpecConstr+    || any (forceSpecArgTy env) tys  forceSpecArgTy _ _ = False @@ -1944,7 +1943,7 @@                   = (spec_lam_args1, spec_lam_args1, spec_arity1, spec_join_arity1)                spec_id    = asWorkerLikeId $-                           mkLocalId spec_name Many+                           mkLocalId spec_name ManyTy                                      (mkLamTypes spec_lam_args spec_body_ty)                              -- See Note [Transfer strictness]                              `setIdDmdSig`    spec_sig@@ -2002,7 +2001,7 @@        , let pat_ty = exprType pat        , typeDeterminesValue pat_ty        , exprFreeVars pat `disjointVarSet` qvar_set-       = do { id <- mkSysLocalOrCoVarM (fsLit "dict") Many pat_ty+       = do { id <- mkSysLocalOrCoVarM (fsLit "dict") ManyTy pat_ty             ; return (id:extra_qvs, Var id) }        | otherwise        = return (extra_qvs, pat)@@ -2710,7 +2709,7 @@ -- | wildCardPats are always boring wildCardPat :: Type -> StrictnessMark -> UniqSM (Bool, CoreArg, [Id]) wildCardPat ty str-  = do { id <- mkSysLocalOrCoVarM (fsLit "sc") Many ty+  = do { id <- mkSysLocalOrCoVarM (fsLit "sc") ManyTy ty        -- ; pprTraceM "wildCardPat" (ppr id' <+> ppr (idUnfolding id'))        ; return (False, varToCoreExpr id, if isMarkedStrict str then [id] else []) } 
compiler/GHC/Core/Opt/Specialise.hs view
@@ -17,6 +17,7 @@  import GHC.Core.Type  hiding( substTy, substCo, extendTvSubst, zapSubst ) import GHC.Core.Multiplicity+import GHC.Core.SimpleOpt( defaultSimpleOpts, simpleOptExprWith ) import GHC.Core.Predicate import GHC.Core.Coercion( Coercion ) import GHC.Core.Opt.Monad@@ -30,7 +31,6 @@                           , mkCast, exprType                           , stripTicksTop, mkInScopeSetBndrs ) import GHC.Core.FVs-import GHC.Core.TyCo.Rep ( TyCoBinder (..) ) import GHC.Core.TyCo.FVs ( tyCoVarsOfTypeList ) import GHC.Core.Opt.Arity( collectBindersPushingCo ) @@ -47,7 +47,7 @@ import GHC.Types.Name import GHC.Types.Tickish import GHC.Types.Id.Make  ( voidArgId, voidPrimId )-import GHC.Types.Var      ( isLocalVar )+import GHC.Types.Var      ( PiTyBinder(..), isLocalVar, isInvisibleFunArg ) import GHC.Types.Var.Set import GHC.Types.Var.Env import GHC.Types.Id@@ -58,7 +58,6 @@ import GHC.Utils.Misc import GHC.Utils.Outputable import GHC.Utils.Panic-import GHC.Utils.Trace  import GHC.Unit.Module( Module ) import GHC.Unit.Module.ModGuts@@ -637,9 +636,11 @@ -- | Specialise calls to type-class overloaded functions occurring in a program. specProgram :: ModGuts -> CoreM ModGuts specProgram guts@(ModGuts { mg_module = this_mod-                          , mg_rules = local_rules-                          , mg_binds = binds })-  = do { dflags <- getDynFlags+                          , mg_rules  = local_rules+                          , mg_binds  = binds })+  = do { dflags   <- getDynFlags+       ; rule_env <- initRuleEnv guts+                     -- See Note [Fire rules in the specialiser]                -- We need to start with a Subst that knows all the things               -- that are in scope, so that the substitution engine doesn't@@ -651,6 +652,7 @@                                       --    mkInScopeSetList $                                       --  bindersOfBinds binds                           , se_module = this_mod+                          , se_rules  = rule_env                           , se_dflags = dflags }               go []           = return ([], emptyUDs)@@ -661,7 +663,7 @@              -- Specialise the bindings of this module        ; (binds', uds) <- runSpecM (go binds) -       ; (spec_rules, spec_binds) <- specImports top_env local_rules uds+       ; (spec_rules, spec_binds) <- specImports top_env uds         ; return (guts { mg_binds = spec_binds ++ binds'                       , mg_rules = spec_rules ++ local_rules }) }@@ -726,21 +728,15 @@ -}  specImports :: SpecEnv-            -> [CoreRule]             -> UsageDetails             -> CoreM ([CoreRule], [CoreBind])-specImports top_env local_rules-            (MkUD { ud_binds = dict_binds, ud_calls = calls })+specImports top_env (MkUD { ud_binds = dict_binds, ud_calls = calls })   | not $ gopt Opt_CrossModuleSpecialise (se_dflags top_env)     -- See Note [Disabling cross-module specialisation]   = return ([], wrapDictBinds dict_binds [])    | otherwise-  = do { hpt_rules <- getRuleBase-       ; let rule_base = extendRuleBaseList hpt_rules local_rules--       ; (spec_rules, spec_binds) <- spec_imports top_env [] rule_base-                                                  dict_binds calls+  = do { (_env, spec_rules, spec_binds) <- spec_imports top_env [] dict_binds calls               -- Don't forget to wrap the specialized bindings with              -- bindings for the needed dictionaries.@@ -758,89 +754,91 @@ spec_imports :: SpecEnv          -- Passed in so that all top-level Ids are in scope              -> [Id]             -- Stack of imported functions being specialised                                  -- See Note [specImport call stack]-             -> RuleBase         -- Rules from this module and the home package-                                 -- (but not external packages, which can change)              -> FloatedDictBinds -- Dict bindings, used /only/ for filterCalls                                  -- See Note [Avoiding loops in specImports]              -> CallDetails      -- Calls for imported things-             -> CoreM ( [CoreRule]   -- New rules+             -> CoreM ( SpecEnv      -- Env contains the new rules+                      , [CoreRule]   -- New rules                       , [CoreBind] ) -- Specialised bindings-spec_imports top_env callers rule_base dict_binds calls+spec_imports env callers dict_binds calls   = do { let import_calls = dVarEnvElts calls --       ; debugTraceMsg (text "specImports {" <+> --                         vcat [ text "calls:" <+> ppr import_calls --                              , text "dict_binds:" <+> ppr dict_binds ])-       ; (rules, spec_binds) <- go rule_base import_calls+       ; (env, rules, spec_binds) <- go env import_calls --       ; debugTraceMsg (text "End specImports }" <+> ppr import_calls) -       ; return (rules, spec_binds) }+       ; return (env, rules, spec_binds) }   where-    go :: RuleBase -> [CallInfoSet] -> CoreM ([CoreRule], [CoreBind])-    go _ [] = return ([], [])-    go rb (cis : other_calls)+    go :: SpecEnv -> [CallInfoSet] -> CoreM (SpecEnv, [CoreRule], [CoreBind])+    go env [] = return (env, [], [])+    go env (cis : other_calls)       = do { -- debugTraceMsg (text "specImport {" <+> ppr cis)-           ; (rules1, spec_binds1) <- spec_import top_env callers rb dict_binds cis+           ; (env, rules1, spec_binds1) <- spec_import env callers dict_binds cis            ; -- debugTraceMsg (text "specImport }" <+> ppr cis) -           ; (rules2, spec_binds2) <- go (extendRuleBaseList rb rules1) other_calls-           ; return (rules1 ++ rules2, spec_binds1 ++ spec_binds2) }+           ; (env, rules2, spec_binds2) <- go env other_calls+           ; return (env, rules1 ++ rules2, spec_binds1 ++ spec_binds2) }  spec_import :: SpecEnv               -- Passed in so that all top-level Ids are in scope             -> [Id]                  -- Stack of imported functions being specialised                                      -- See Note [specImport call stack]-            -> RuleBase              -- Rules from this module             -> FloatedDictBinds      -- Dict bindings, used /only/ for filterCalls                                      -- See Note [Avoiding loops in specImports]             -> CallInfoSet           -- Imported function and calls for it-            -> CoreM ( [CoreRule]    -- New rules+            -> CoreM ( SpecEnv+                     , [CoreRule]    -- New rules                      , [CoreBind] )  -- Specialised bindings-spec_import top_env callers rb dict_binds cis@(CIS fn _)+spec_import env callers dict_binds cis@(CIS fn _)   | isIn "specImport" fn callers-  = return ([], [])     -- No warning.  This actually happens all the time-                        -- when specialising a recursive function, because-                        -- the RHS of the specialised function contains a recursive-                        -- call to the original function+  = return (env, [], [])  -- No warning.  This actually happens all the time+                          -- when specialising a recursive function, because+                          -- the RHS of the specialised function contains a recursive+                          -- call to the original function    | null good_calls-  = return ([], [])+  = return (env, [], [])    | Just rhs <- canSpecImport dflags fn   = do {     -- Get rules from the external package state              -- We keep doing this in case we "page-fault in"              -- more rules as we go along-       ; external_rule_base <- getExternalRuleBase-       ; vis_orphs <- getVisibleOrphanMods-       ; let rules_for_fn = getRules (RuleEnv [rb, external_rule_base] vis_orphs) fn+       ; eps_rules <- getExternalRuleBase+       ; let rule_env = se_rules env `updExternalPackageRules` eps_rules -       ; -- debugTraceMsg (text "specImport1" <+> vcat [ppr fn, ppr good_calls, ppr rhs])+--       ; debugTraceMsg (text "specImport1" <+> vcat [ppr fn, ppr good_calls+--                                                    , ppr (getRules rule_env fn), ppr rhs])        ; (rules1, spec_pairs, MkUD { ud_binds = dict_binds1, ud_calls = new_calls })-            <- runSpecM $ specCalls True top_env dict_binds-                             rules_for_fn good_calls fn rhs+            <- runSpecM $ specCalls True env dict_binds+                                    (getRules rule_env fn) good_calls fn rhs         ; let spec_binds1 = [NonRec b r | (b,r) <- spec_pairs]              -- After the rules kick in we may get recursion, but              -- we rely on a global GlomBinds to sort that out later              -- See Note [Glom the bindings if imported functions are specialised] +             new_subst = se_subst env `Core.extendSubstInScopeList` map fst spec_pairs+             new_env   = env { se_rules = rule_env `addLocalRules` rules1+                             , se_subst = new_subst }+               -- Now specialise any cascaded calls-       ; -- debugTraceMsg (text "specImport 2" <+> (ppr fn $$ ppr rules1 $$ ppr spec_binds1))-       ; (rules2, spec_binds2) <- spec_imports top_env-                                               (fn:callers)-                                               (extendRuleBaseList rb rules1)-                                               (dict_binds `thenFDBs` dict_binds1)-                                               new_calls+--       ; debugTraceMsg (text "specImport 2" <+> (ppr fn $$ ppr rules1 $$ ppr spec_binds1))+       ; (env, rules2, spec_binds2)+            <- spec_imports new_env (fn:callers)+                                    (dict_binds `thenFDBs` dict_binds1)+                                    new_calls         ; let final_binds = wrapDictBinds dict_binds1 $                            spec_binds2 ++ spec_binds1 -       ; return (rules2 ++ rules1, final_binds) }+       ; return (env, rules2 ++ rules1, final_binds) }    | otherwise   = do { tryWarnMissingSpecs dflags callers fn good_calls-       ; return ([], [])}+       ; return (env, [], [])}    where-    dflags = se_dflags top_env+    dflags = se_dflags env     good_calls = filterCalls cis dict_binds        -- SUPER IMPORTANT!  Drop calls that (directly or indirectly) refer to fn        -- See Note [Avoiding loops in specImports]@@ -1135,6 +1133,7 @@              --    the RHS of specialised bindings (no type-let!)         , se_module :: Module+       , se_rules  :: RuleEnv  -- From the home package and this module        , se_dflags :: DynFlags      } @@ -1173,8 +1172,8 @@        ; (args_out, uds_args) <- mapAndCombineSM (specExpr env) args_in        ; let env_args = env `bringFloatedDictsIntoScope` ud_binds uds_args                 -- Some dicts may have floated out of args_in;-                -- they should be in scope for rewriteClassOps (#21689)-             (fun_in', args_out') = rewriteClassOps env_args fun_in args_out+                -- they should be in scope for fireRewriteRules (#21689)+             (fun_in', args_out') = fireRewriteRules env_args fun_in args_out        ; (fun_out', uds_fun) <- specExpr env fun_in'        ; let uds_call = mkCallUDs env fun_out' args_out'        ; return (fun_out' `mkApps` args_out', uds_fun `thenUDs` uds_call `thenUDs` uds_args) }@@ -1209,17 +1208,19 @@        ; return (foldr Let body' binds', uds) }  -- See Note [Specialisation modulo dictionary selectors]--- and Note [ClassOp/DFun selection]-rewriteClassOps :: SpecEnv -> InExpr -> [OutExpr] -> (InExpr, [OutExpr])-rewriteClassOps env (Var f) args-  | isClassOpId f -- If we see `op_sel $fCInt`, we rewrite to `$copInt`-  , Just (rule, expr) <- -- pprTrace "rewriteClassOps" (ppr f $$ ppr args $$ ppr (se_subst env)) $-                         specLookupRule env f args (idCoreRules f)-  , let rest_args = drop (ruleArity rule) args -- See Note [Extra args in the target]---  , pprTrace "class op rewritten" (ppr f <+> ppr args $$ ppr expr <+> ppr rest_args) True-  , (fun, args) <- collectArgs expr-  = rewriteClassOps env fun (args++rest_args)-rewriteClassOps _ fun args = (fun, args)+--     Note [ClassOp/DFun selection]+--     Note [Fire rules in the specialiser]+fireRewriteRules :: SpecEnv -> InExpr -> [OutExpr] -> (InExpr, [OutExpr])+fireRewriteRules env (Var f) args+  | Just (rule, expr) <- specLookupRule env f args InitialPhase (getRules (se_rules env) f)+  , let rest_args    = drop (ruleArity rule) args -- See Note [Extra args in the target]+        zapped_subst = Core.zapSubst (se_subst env)+        expr'        = simpleOptExprWith defaultSimpleOpts zapped_subst expr+                       -- simplOptExpr needed because lookupRule returns+                       --   (\x y. rhs) arg1 arg2+  , (fun, args) <- collectArgs expr'+  = fireRewriteRules env fun (args++rest_args)+fireRewriteRules _ fun args = (fun, args)  -------------- specLam :: SpecEnv -> [OutBndr] -> InExpr -> SpecM (OutExpr, UsageDetails)@@ -1325,7 +1326,67 @@         where           (env_rhs, args') = substBndrs env_alt args -{-+{- Note [Fire rules in the specialiser]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this (#21851)++    module A where+      f :: Num b => b -> (b, b)+      f x = (x + 1, snd (f x))+      {-# SPECIALIZE f :: Int -> (Int, Int) #-}++    module B (g') where+      import A++      g :: Num a => a -> a+      g x = fst (f x)+      {-# NOINLINE[99] g #-}++      h :: Int -> Int+      h = g++Note that `f` has the CPR property, and so will worker/wrapper.++The call to `g` in `h` will make us specialise `g @Int`. And the specialised+version of `g` will contain the call `f @Int`; but in the subsequent run of+the Simplifier, there will be a competition between:+* The user-supplied SPECIALISE rule for `f`+* The inlining of the wrapper for `f`+In fact, the latter wins -- see Note [Rewrite rules and inlining] in+GHC.Core.Opt.Simplify.Iteration.  However, it a bit fragile.++Moreover consider (test T21851_2):++    module A+      f :: (Ord a, Show b) => a -> b -> blah+      {-# RULE forall b. f @Int @b = wombat #-}++      wombat :: Show b => Int -> b -> blah+      wombat = blah++    module B+      import A+      g :: forall a. Ord a => blah+      g @a = ...g...f @a @Char....++      h = ....g @Int....++Now, in module B, GHC will specialise `g @Int`, which will lead to a+call `f @Int @Char`.  If we immediately (in the specialiser) rewrite+that to `womabat @Char`, we have a chance to specialise `wombat`.++Conclusion: it's treat if the Specialiser fires RULEs itself.+It's not hard to achieve: see `fireRewriteRules`. The only tricky bit is+making sure that we have a reasonably up to date EPS rule base. Currently+we load it up just once, in `initRuleEnv`, called at the beginning of+`specProgram`.++NB: you might wonder if running rules in the specialiser (this Note)+renders Note [Rewrite rules and inlining] in the Simplifier redundant.+That is, if we run rules in the specialiser, does it matter if we make+rules "win" over inlining in the Simplifier?  Yes, it does!  See the+discussion in #21851.+ Note [Floating dictionaries out of cases] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Consider@@ -1416,13 +1477,12 @@               final_binds :: [DictBind]              -- See Note [From non-recursive to recursive]-             final_binds-               | not (isNilOL dump_dbs)-               , not (null spec_defns)-               = [recWithDumpedDicts pairs dump_dbs]-               | otherwise-               = [mkDB $ NonRec b r | (b,r) <- pairs]-                 ++ fromOL dump_dbs+             final_binds | not (isNilOL dump_dbs)+                         , not (null spec_defns)+                         = [recWithDumpedDicts pairs dump_dbs]+                         | otherwise+                         = [mkDB $ NonRec b r | (b,r) <- pairs]+                           ++ fromOL dump_dbs         ; if float_all then              -- Rather than discard the calls mentioning the bound variables@@ -1554,8 +1614,10 @@     foldlM spec_call ([], [], emptyUDs) calls_for_me    | otherwise   -- No calls or RHS doesn't fit our preconceptions-  = warnPprTrace (not (exprIsTrivial rhs) && notNull calls_for_me)+  = warnPprTrace (not (exprIsTrivial rhs) && notNull calls_for_me && not (isClassOpId fn))           "Missed specialisation opportunity for" (ppr fn $$ trace_doc) $+          -- isClassOpId: class-op Ids never inline; we specialise them+          -- through fireRewriteRules. So don't complain about missed opportunities           -- Note [Specialisation shape]     -- pprTrace "specCalls: none" (ppr fn <+> ppr calls_for_me) $     return ([], [], emptyUDs)@@ -1582,9 +1644,13 @@      already_covered :: SpecEnv -> [CoreRule] -> [CoreExpr] -> Bool     already_covered env new_rules args      -- Note [Specialisations already covered]-       = isJust (specLookupRule env fn args (new_rules ++ existing_rules))-         -- NB: we look both in the new_rules (generated by this invocation-         --     of specCalls), and in existing_rules (passed in to specCalls)+       = isJust (specLookupRule env fn args (beginPhase inl_act)+                                (new_rules ++ existing_rules))+         -- Rules: we look both in the new_rules (generated by this invocation+         --   of specCalls), and in existing_rules (passed in to specCalls)+         -- inl_act: is the activation we are going to put in the new SPEC+         --   rule; so we want to see if it is covered by another rule with+         --   that same activation.      ----------------------------------------------------------         -- Specialise to one particular call pattern@@ -1709,13 +1775,16 @@  -- Convenience function for invoking lookupRule from Specialise -- The SpecEnv's InScopeSet should include all the Vars in the [CoreExpr]-specLookupRule :: SpecEnv -> Id -> [CoreExpr] -> [CoreRule] -> Maybe (CoreRule, CoreExpr)-specLookupRule env fn args rules-  = lookupRule ropts (in_scope, realIdUnfolding) (const True) fn args rules+specLookupRule :: SpecEnv -> Id -> [CoreExpr]+               -> CompilerPhase  -- Look up rules as if we were in this phase+               -> [CoreRule] -> Maybe (CoreRule, CoreExpr)+specLookupRule env fn args phase rules+  = lookupRule ropts (in_scope, realIdUnfolding) is_active fn args rules   where-    dflags   = se_dflags env-    in_scope = getSubstInScope (se_subst env)-    ropts    = initRuleOpts dflags+    dflags    = se_dflags env+    in_scope  = getSubstInScope (se_subst env)+    ropts     = initRuleOpts dflags+    is_active = isActive phase  {- Note [Specialising DFuns] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~@@ -1914,10 +1983,10 @@ the Specialiser. Hence  1. In the App case of 'specExpr', try to apply the ClassOp/DFun rule on the-   head of the application, repeatedly, via 'rewriteClassOps'.+   head of the application, repeatedly, via 'fireRewriteRules'. 2. Attach an unfolding to freshly-bound dictionary ids such as `$dC` and    `$dShow` in `bindAuxiliaryDict`, so that we can exploit the unfolding-   in 'rewriteClassOps' to do the ClassOp/DFun rewrite.+   in 'fireRewriteRules' to do the ClassOp/DFun rewrite.  NB: Without (2), (1) would be pointless, because 'lookupRule' wouldn't be able to look into the RHS of `$dC` to see the DFun.@@ -2785,8 +2854,8 @@ callInfoFVs (CIS _ call_info) =   foldr (\(CI { ci_fvs = fv }) vs -> unionVarSet fv vs) emptyVarSet call_info -getTheta :: [TyCoBinder] -> [PredType]-getTheta = fmap tyBinderType . filter isInvisibleBinder . filter (not . isNamedBinder)+getTheta :: [PiTyBinder] -> [PredType]+getTheta = fmap piTyBinderType . filter isInvisiblePiTyBinder . filter isAnonPiTyBinder   ------------------------------------------------------------@@ -2835,7 +2904,7 @@              -- which broadens its applicability, since rules only              -- fire when saturated -    mk_spec_arg :: OutExpr -> TyCoBinder -> SpecArg+    mk_spec_arg :: OutExpr -> PiTyBinder -> SpecArg     mk_spec_arg arg (Named bndr)       |  binderVar bndr `elemVarSet` constrained_tyvars       = case arg of@@ -2843,19 +2912,17 @@           _       -> pprPanic "ci_key" $ ppr arg       |  otherwise = UnspecType -    -- For "InvisArg", which are the type-class dictionaries,+    -- For "invisibleFunArg", which are the type-class dictionaries,     -- we decide on a case by case basis if we want to specialise     -- on this argument; if so, SpecDict, if not UnspecArg-    mk_spec_arg arg (Anon InvisArg pred)-      | interestingDict arg (scaledThing pred)+    mk_spec_arg arg (Anon pred af)+      | isInvisibleFunArg af+      , interestingDict arg (scaledThing pred)               -- See Note [Interesting dictionary arguments]       = SpecDict arg        | otherwise = UnspecArg -    mk_spec_arg _ (Anon VisArg _)-      = UnspecArg- {- Note [Ticks on applications] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~@@ -3277,7 +3344,7 @@   = do { uniq <- getUniqueM        ; let n    = idName b              ty'  = substTyUnchecked subst (idType b)-             b'   = mkUserLocal (nameOccName n) uniq Many ty' (getSrcSpan n)+             b'   = mkUserLocal (nameOccName n) uniq ManyTy ty' (getSrcSpan n)              env' = env { se_subst = subst `Core.extendSubstInScope` b' }        ; pure (env', b') } @@ -3287,7 +3354,7 @@   = do  { uniq <- getUniqueM         ; let name    = idName old_id               new_occ = mkSpecOcc (nameOccName name)-              new_id  = mkUserLocal new_occ uniq Many new_ty (getSrcSpan name)+              new_id  = mkUserLocal new_occ uniq ManyTy new_ty (getSrcSpan name)                           `asJoinId_maybe` join_arity_maybe         ; return new_id } 
compiler/GHC/Core/Opt/StaticArgs.hs view
@@ -54,20 +54,23 @@  import GHC.Prelude -import GHC.Types.Var import GHC.Core import GHC.Core.Utils import GHC.Core.Type import GHC.Core.Coercion+import GHC.Core.TyCo.Compare( eqType )++import GHC.Types.Var import GHC.Types.Id import GHC.Types.Name import GHC.Types.Var.Env import GHC.Types.Unique.Supply-import GHC.Utils.Misc import GHC.Types.Unique.FM import GHC.Types.Var.Set import GHC.Types.Unique import GHC.Types.Unique.Set++import GHC.Utils.Misc import GHC.Utils.Outputable import GHC.Utils.Panic @@ -420,13 +423,13 @@           shadow_rhs = mkLams shadow_lam_bndrs local_body             -- nonrec_rhs = \alpha' beta' c n xs -> sat_worker xs -          rec_body_bndr = mkSysLocal (fsLit "sat_worker") uniq Many (exprType rec_body)+          rec_body_bndr = mkSysLocal (fsLit "sat_worker") uniq ManyTy (exprType rec_body)             -- rec_body_bndr = sat_worker              -- See Note [Shadow binding]; make a SysLocal           shadow_bndr = mkSysLocal (occNameFS (getOccName binder))                                    (idUnique binder)-                                   Many+                                   ManyTy                                    (exprType shadow_rhs)  isStaticValue :: Staticness App -> Bool
compiler/GHC/Core/Opt/WorkWrap.hs view
@@ -35,7 +35,6 @@ import GHC.Utils.Panic import GHC.Utils.Panic.Plain import GHC.Utils.Monad-import GHC.Utils.Trace import GHC.Core.DataCon  {-
compiler/GHC/Core/Opt/WorkWrap/Utils.hs view
@@ -15,7 +15,7 @@    , findTypeShape, IsRecDataConResult(..), isRecDataCon    , mkAbsentFiller    , isWorkerSmallEnough, dubiousDataConInstArgTys-   , isGoodWorker, badWorker , goodWorker+   , boringSplit , usefulSplit    ) where @@ -56,7 +56,6 @@ import GHC.Utils.Outputable import GHC.Utils.Panic import GHC.Utils.Panic.Plain-import GHC.Utils.Trace  import Control.Applicative ( (<|>) ) import Control.Monad ( zipWithM )@@ -572,23 +571,24 @@                             -- returned product was constructed, so unbox it.   | DropAbsent              -- ^ The argument/field was absent. Drop it. --- Do we want to create workers just for unlifting?-wwForUnlifting :: WwOpts -> Bool-wwForUnlifting !opts+-- | Do we want to create workers just for unlifting?+wwUseForUnlifting :: WwOpts -> WwUse+wwUseForUnlifting !opts     -- Always unlift if possible-    | wo_unlift_strict opts = goodWorker+    | wo_unlift_strict opts = usefulSplit     -- Don't unlift  it would cause additional W/W splits.-    | otherwise = badWorker--badWorker :: Bool-badWorker = False+    | otherwise             = boringSplit -goodWorker :: Bool-goodWorker = True+-- | Is the worker/wrapper split profitable?+type WwUse = Bool -isGoodWorker :: Bool -> Bool-isGoodWorker = id+-- | WW split not profitable+boringSplit :: WwUse+boringSplit = False +-- | WW split profitable+usefulSplit :: WwUse+usefulSplit = True  -- | Unwraps the 'Boxity' decision encoded in the given 'SubDemand' and returns -- a 'DataConPatContext' as well the nested demands on fields of the 'DataCon'@@ -648,8 +648,8 @@ isLinear :: Scaled a -> Bool isLinear (Scaled w _ ) =   case w of-    One -> True-    _ -> False+    OneTy -> True+    _     -> False   {- Note [Which types are unboxed?]@@ -827,7 +827,7 @@ So there is a flag, `-fworker-wrapper-cbv`, to control whether we do w/w on strict arguments (internally `Opt_WorkerWrapperUnlift`).  The flag is off by default.  The choice is made in-GHC.Core.Opt.WorkWrape.Utils.wwForUnlifting+GHC.Core.Opt.WorkWrape.Utils.wwUseForUnlifting  See also `Note [WW for calling convention]` in GHC.Core.Opt.WorkWrap.Utils -}@@ -844,7 +844,7 @@         -> [Var]                         -- Wrapper args; have their demand info on them                                          --  *Includes type variables*         -> [StrictnessMark]              -- Strictness-mark info for arguments-        -> UniqSM (Bool,                 -- Will this result in a useful worker+        -> UniqSM (WwUse,                -- Will this result in a useful worker                    [(Var,StrictnessMark)],      -- Worker args/their call-by-value semantics.                    CoreExpr -> CoreExpr, -- Wrapper body, lacking the worker call                                          -- and without its lambdas@@ -856,7 +856,7 @@   = -- pprTrace "mkWWstr" (ppr args) $     go args str_marks   where-    go [] _ = return (badWorker, [], nop_fn, [])+    go [] _ = return (boringSplit, [], nop_fn, [])     go (arg : args) (str:strs)       = do { (useful1, args1, wrap_fn1, wrap_arg)  <- mkWWstr_one opts arg str            ; (useful2, args2, wrap_fn2, wrap_args) <- go args strs@@ -876,7 +876,7 @@ mkWWstr_one :: WwOpts             -> Var             -> StrictnessMark-            -> UniqSM (Bool, [(Var,StrictnessMark)], CoreExpr -> CoreExpr, CoreExpr)+            -> UniqSM (WwUse, [(Var,StrictnessMark)], CoreExpr -> CoreExpr, CoreExpr) mkWWstr_one opts arg str_mark =   -- pprTrace "mkWWstr_one" (ppr arg <+> (if isId arg then ppr arg_ty  $$ ppr arg_dmd else text "type arg")) $   case canUnboxArg fam_envs arg_ty arg_dmd of@@ -888,7 +888,7 @@          -- We can't always handle absence for arbitrary          -- unlifted types, so we need to choose just the cases we can          -- (that's what mkAbsentFiller does)-      -> return (goodWorker, [], nop_fn, absent_filler)+      -> return (usefulSplit, [], nop_fn, absent_filler)       | otherwise -> do_nothing      DoUnbox dcpc -> -- pprTrace "mkWWstr_one:1" (ppr (dcpc_dc dcpc) <+> ppr (dcpc_tc_args dcpc) $$ ppr (dcpc_args dcpc)) $@@ -896,12 +896,12 @@      DontUnbox       | isStrictDmd arg_dmd || isMarkedStrict str_mark-      , wwForUnlifting opts  -- See Note [CBV Function Ids]+      , wwUseForUnlifting opts  -- See Note [CBV Function Ids]       , not (isFunTy arg_ty)       , not (isUnliftedType arg_ty) -- Already unlifted!         -- NB: function arguments have a fixed RuntimeRep,         -- so it's OK to call isUnliftedType here-      -> return  (goodWorker, [(arg, MarkedStrict)], nop_fn, varToCoreExpr arg )+      -> return  (usefulSplit, [(arg, MarkedStrict)], nop_fn, varToCoreExpr arg )        | otherwise -> do_nothing @@ -911,11 +911,11 @@     arg_dmd    = idDemandInfo arg     arg_str    | isTyVar arg = NotMarkedStrict -- Type args don't get strictness marks                | otherwise   = str_mark-    do_nothing = return (badWorker, [(arg,arg_str)], nop_fn, varToCoreExpr arg)+    do_nothing = return (boringSplit, [(arg,arg_str)], nop_fn, varToCoreExpr arg)  unbox_one_arg :: WwOpts-              -> Var-> DataConPatContext Demand-              -> UniqSM (Bool, [(Var,StrictnessMark)], CoreExpr -> CoreExpr, CoreExpr)+              -> Var -> DataConPatContext Demand+              -> UniqSM (WwUse, [(Var,StrictnessMark)], CoreExpr -> CoreExpr, CoreExpr) unbox_one_arg opts arg_var               DataConPatContext { dcpc_dc = dc, dcpc_tc_args = tc_args                                 , dcpc_co = co, dcpc_args = ds }@@ -940,13 +940,14 @@              -- See Note [Call-by-value for worker args]              all_str_marks = (map (const NotMarkedStrict) ex_tvs') ++ con_str_marks -       ; (_sub_args_quality, worker_args, wrap_fn, wrap_args)+       ; (nested_useful, worker_args, wrap_fn, wrap_args)              <- mkWWstr opts (ex_tvs' ++ arg_ids') all_str_marks         ; let wrap_arg = mkConApp dc (map Type tc_args ++ wrap_args) `mkCast` mkSymCo co--       ; return (goodWorker, worker_args, unbox_fn . wrap_fn, wrap_arg) }-                          -- Don't pass the arg, rebox instead+       -- See Note [Unboxing through unboxed tuples]+       ; return $ if isUnboxedTupleDataCon dc && not nested_useful+                     then (boringSplit, [(arg_var,NotMarkedStrict)], nop_fn, varToCoreExpr arg_var)+                     else (usefulSplit, worker_args, unbox_fn . wrap_fn, wrap_arg) }  -- | Tries to find a suitable absent filler to bind the given absent identifier -- to. See Note [Absent fillers].@@ -1196,6 +1197,26 @@    because `MkT` is strict in its Int# argument, so we get an absentError    exception when we shouldn't.  Very annoying! +Note [Unboxing through unboxed tuples]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We should not to a worker/wrapper split just for unboxing the components of+an unboxed tuple (in the result *or* argument, #22388). Consider+  boring_res x y = (# y, x #)+It's entirely pointless to split for the constructed unboxed pair to+  $wboring_res x y = (# y, x #)+  boring_res = case $wboring_res x y of (# a, b #) -> (# a, b #)+`boring_res` will immediately simplify to an alias for `$wboring_res`!++Similarly, the unboxed tuple might occur in argument position+  boring_arg (# x, y, z #) = (# z, x, y #)+It's entirely pointless to "unbox" the triple+  $wboring_arg x y z = (# z, x, y #)+  boring_arg (# x, y, z #) = $wboring_arg x y z+because after unarisation, `boring_arg` is just an alias for `$wboring_arg`.++Conclusion: Only consider unboxing an unboxed tuple useful when we will+also unbox its components. That is governed by the `usefulSplit` mechanism.+ ************************************************************************ *                                                                      *          Type scrutiny that is specific to demand analysis@@ -1227,7 +1248,7 @@        -- to look deep into such products -- see #18034   where     go rec_tc ty-       | Just (_, _, res) <- splitFunTy_maybe ty+       | Just (_, _, _, res) <- splitFunTy_maybe ty        = TsFun (go rec_tc res)         | Just (tc, tc_args)  <- splitTyConApp_maybe ty@@ -1377,12 +1398,12 @@   :: WwOpts   -> Type                              -- function body   -> Cpr                               -- CPR analysis results-  -> UniqSM (Bool,            -- Is w/w'ing useful?+  -> UniqSM (WwUse,                    -- Is w/w'ing useful?              CoreExpr -> CoreExpr,     -- New wrapper. 'nop_fn' if not useful              CoreExpr -> CoreExpr)     -- New worker.  'nop_fn' if not useful -- ^ Entrypoint to CPR W/W. See Note [Worker/wrapper for CPR] for an overview. mkWWcpr_entry opts body_ty body_cpr-  | not (wo_cpr_anal opts) = return (badWorker, nop_fn, nop_fn)+  | not (wo_cpr_anal opts) = return (boringSplit, nop_fn, nop_fn)   | otherwise = do     -- Part (1)     res_bndr <- mk_res_bndr body_ty@@ -1399,8 +1420,8 @@     let wrap_fn      = unbox_transit_tup rebuilt_result                 -- 3 2         work_fn body = bind_res_bndr body (work_unpack_res transit_tup) -- 1 2 3     return $ if not useful-                then (badWorker, nop_fn, nop_fn)-                else (goodWorker, wrap_fn, work_fn)+                then (boringSplit, nop_fn, nop_fn)+                else (usefulSplit, wrap_fn, work_fn)  -- | Part (1) of Note [Worker/wrapper for CPR]. mk_res_bndr :: Type -> UniqSM Id@@ -1412,18 +1433,18 @@  -- | What part (2) of Note [Worker/wrapper for CPR] collects. -----   1. A Bool capturing whether the transformation did anything useful.+--   1. A 'WwUse' capturing whether the split does anything useful. --   2. The list of transit variables (see the Note). --   3. The result builder expression for the wrapper.  The original case binder if not useful. --   4. The result unpacking expression for the worker. 'nop_fn' if not useful.-type CprWwResultOne  = (Bool, OrdList Var,  CoreExpr , CoreExpr -> CoreExpr)-type CprWwResultMany = (Bool, OrdList Var, [CoreExpr], CoreExpr -> CoreExpr)+type CprWwResultOne  = (WwUse, OrdList Var,  CoreExpr , CoreExpr -> CoreExpr)+type CprWwResultMany = (WwUse, OrdList Var, [CoreExpr], CoreExpr -> CoreExpr)  mkWWcpr :: WwOpts -> [Id] -> [Cpr] -> UniqSM CprWwResultMany mkWWcpr _opts vars []   =   -- special case: No CPRs means all top (for example from FlatConCpr),   -- hence stop WW.-  return (badWorker, toOL vars, map varToCoreExpr vars, nop_fn)+  return (boringSplit, toOL vars, map varToCoreExpr vars, nop_fn) mkWWcpr opts  vars cprs = do   -- No existentials in 'vars'. 'canUnboxResult' should have checked that.   massertPpr (not (any isTyVar vars)) (ppr vars $$ ppr cprs)@@ -1442,7 +1463,7 @@   , DoUnbox dcpc <- canUnboxResult (wo_fam_envs opts) (idType res_bndr) cpr   = unbox_one_result opts res_bndr dcpc   | otherwise-  = return (badWorker, unitOL res_bndr, varToCoreExpr res_bndr, nop_fn)+  = return (boringSplit, unitOL res_bndr, varToCoreExpr res_bndr, nop_fn)  unbox_one_result   :: WwOpts -> Id -> DataConPatContext Cpr -> UniqSM CprWwResultOne@@ -1468,11 +1489,10 @@       -- this_work_unbox_res alt = (case res_bndr |> co of C a b -> <alt>[a,b])       this_work_unbox_res = mkUnpackCase (Var res_bndr) co cprCaseBndrMult dc arg_ids -  -- Don't try to WW an unboxed tuple return type when there's nothing inside-  -- to unbox further.+  -- See Note [Unboxing through unboxed tuples]   return $ if isUnboxedTupleDataCon dc && not nested_useful-              then ( badWorker, unitOL res_bndr, Var res_bndr, nop_fn )-              else ( goodWorker+              then ( boringSplit, unitOL res_bndr, Var res_bndr, nop_fn )+              else ( usefulSplit                    , transit_vars                    , rebuilt_result                    , this_work_unbox_res . work_unbox_res@@ -1506,7 +1526,7 @@                                     (DataAlt tup_con) vars build_res     , ubx_tup_app )    where-    ubx_tup_app = mkCoreUbxTup (map idType vars) (map varToCoreExpr vars)+    ubx_tup_app = mkCoreUnboxedTuple (map varToCoreExpr vars)     tup_con     = tupleDataCon Unboxed (length vars)     -- See also Note [Linear types and CPR]     case_bndr   = mkWildValBinder cprCaseBndrMult (exprType ubx_tup_app)@@ -1635,7 +1655,7 @@ -- | The multiplicity of a case binder unboxing a constructed result. -- See Note [Linear types and CPR] cprCaseBndrMult :: Mult-cprCaseBndrMult = One+cprCaseBndrMult = OneTy  ww_prefix :: FastString ww_prefix = fsLit "ww"
compiler/GHC/CoreToStg.hs view
@@ -38,7 +38,7 @@ import GHC.Types.Tickish import GHC.Types.Var.Env import GHC.Types.Name   ( isExternalName, nameModule_maybe )-import GHC.Types.Basic  ( Arity )+import GHC.Types.Basic  ( Arity, TypeOrConstraint(..) ) import GHC.Types.Literal import GHC.Types.ForeignCall import GHC.Types.IPE@@ -56,7 +56,6 @@ import GHC.Utils.Misc (HasDebugCallStack) import GHC.Utils.Panic import GHC.Utils.Panic.Plain-import GHC.Utils.Trace  import Control.Monad (ap) import Data.Maybe (fromMaybe)@@ -405,7 +404,7 @@                                          --    Recompute representation, because in                                          --    '(RUBBISH[rep] x) :: (T :: TYPE rep2)'                                          --    rep might not be equal to rep2-            -> return (StgLit $ LitRubbish $ getRuntimeRep (exprType expr))+            -> return (StgLit $ LitRubbish TypeLike $ getRuntimeRep (exprType expr))        _     -> pprPanic "coreToStgExpr - Invalid app head:" (ppr expr)     where@@ -495,8 +494,7 @@    prim_reps = typePrimRep bndr_ty     _is_poly_alt_tycon tc-        =  isFunTyCon tc-        || isPrimTyCon tc   -- "Any" is lifted but primitive+        =  isPrimTyCon tc   -- "Any" is lifted but primitive         || isFamilyTyCon tc -- Type family; e.g. Any, or arising from strict                             -- function application where argument has a                             -- type-family type
compiler/GHC/CoreToStg/Prep.hs view
@@ -55,7 +55,6 @@ import GHC.Utils.Outputable import GHC.Utils.Monad  ( mapAccumLM ) import GHC.Utils.Logger-import GHC.Utils.Trace  import GHC.Types.Demand import GHC.Types.Var@@ -113,6 +112,17 @@     and doing so would be tiresome because then we'd need     to substitute in types and coercions. +    We need to clone ids for two reasons:+    + Things associated with labels in the final code must be truly unique in+      order to avoid labels being shadowed in the final output.+    + Even binders without info tables like function arguments or alternative+      bound binders must be unique at least in their type/unique combination.+      We only emit a single declaration for each binder when compiling to C+      so if binders are not unique we would either get duplicate declarations+      or misstyped variables. The later happend in #22402.+    + We heavily use unique-keyed maps in the backend which can go wrong when+      ids with the same unique are meant to represent the same variable.+ 7.  Give each dynamic CCall occurrence a fresh unique; this is     rather like the cloning step above. @@ -1047,7 +1057,8 @@     cpe_app env (Var f) (CpeApp Type{} : CpeApp arg : args)         | f `hasKey` lazyIdKey          -- Replace (lazy a) with a, and             -- See Note [lazyId magic] in GHC.Types.Id.Make-       || f `hasKey` noinlineIdKey      -- Replace (noinline a) with a+       || f `hasKey` noinlineIdKey || f `hasKey` noinlineConstraintIdKey+            -- Replace (noinline a) with a             -- See Note [noinlineId magic] in GHC.Types.Id.Make        || f `hasKey` nospecIdKey        -- Replace (nospec a) with a             -- See Note [nospecId magic] in GHC.Types.Id.Make@@ -2205,7 +2216,7 @@  newVar :: Type -> UniqSM Id newVar ty- = seqType ty `seq` mkSysLocalOrCoVarM (fsLit "sat") Many ty+ = seqType ty `seq` mkSysLocalOrCoVarM (fsLit "sat") ManyTy ty   ------------------------------------------------------------------------------
+ compiler/GHC/Data/Graph/Collapse.hs view
@@ -0,0 +1,264 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module GHC.Data.Graph.Collapse+  ( PureSupernode(..)+  , Supernode(..)+  , collapseInductiveGraph+  , VizCollapseMonad(..)+  , NullCollapseViz(..)+  , runNullCollapse+  , MonadUniqSM(..)+  )+where++import GHC.Prelude++import Control.Exception+import Control.Monad+import Data.List (delete, union, insert, intersect)+import Data.Semigroup++import GHC.Cmm.Dataflow.Label+import GHC.Data.Graph.Inductive.Graph+import GHC.Types.Unique.Supply+import GHC.Utils.Panic+++{-|+Module      : GHC.Data.Graph.Collapse+Description : Implement the "collapsing" algorithm Hecht and Ullman++A control-flow graph is reducible if and only if it is collapsible+according to the definition of Hecht and Ullman (1972).   This module+implements the collapsing algorithm of Hecht and Ullman, and if it+encounters a graph that is not collapsible, it splits nodes until the+graph is fully collapsed.  It then reports what nodes (if any) had to+be split in order to collapse the graph.  The information is used+upstream to node-split Cmm graphs.++The module uses the inductive graph representation cloned from the+Functional Graph Library (Hackage package `fgl`, modules+`GHC.Data.Graph.Inductive.*`.)++-}++-- Full reference to paper: Matthew S. Hecht and Jeffrey D. Ullman+-- (1972).  Flow Graph Reducibility. SIAM J. Comput., 1(2), 188–202.+-- https://doi.org/10.1137/0201014+++------------------ Graph-splitting monad -----------------------++-- | If you want to visualize the graph-collapsing algorithm, create+-- an instance of monad `VizCollapseMonad`.  Each step in the+-- algorithm is announced to the monad as a side effect.  If you don't+-- care about visualization, you would use the `NullCollapseViz`+-- monad, in which these operations are no-ops.++class (Monad m) => MonadUniqSM m where+  liftUniqSM :: UniqSM a -> m a++class (MonadUniqSM m, Graph gr, Supernode s m) => VizCollapseMonad m gr s where+  consumeByInGraph :: Node -> Node -> gr s () -> m ()+  splitGraphAt :: gr s () -> LNode s -> m ()+  finalGraph :: gr s () -> m ()++++-- | The identity monad as a `VizCollapseMonad`.  Use this monad when+-- you want efficiency in graph collapse.+newtype NullCollapseViz a = NullCollapseViz { unNCV :: UniqSM a }+  deriving (Functor, Applicative, Monad, MonadUnique)++instance MonadUniqSM NullCollapseViz where+  liftUniqSM = NullCollapseViz++instance (Graph gr, Supernode s NullCollapseViz) =>+    VizCollapseMonad NullCollapseViz gr s where+  consumeByInGraph _ _ _ = return ()+  splitGraphAt _ _ = return ()+  finalGraph _ = return ()++runNullCollapse :: NullCollapseViz a -> UniqSM a+runNullCollapse = unNCV+++------------------ Utility functions on graphs -----------------------+++-- | Tell if a `Node` has a single predecessor.+singlePred :: Graph gr => gr a b -> Node -> Bool+singlePred gr n+    | ([_], _, _, _) <- context gr n = True+    | otherwise = False++-- | Use this function to extract information about a `Node` that you+-- know is in a `Graph`.  It's like `match` from `Graph`, but it must+-- succeed.+forceMatch :: (Graph gr)+           => Node -> gr s b -> (Context s b, gr s b)+forceMatch node g = case match node g of (Just c, g') -> (c, g')+                                         _ -> panicDump node g+ where panicDump :: Graph gr => Node -> gr s b -> any+       panicDump k _g =+         panic $ "GHC.Data.Graph.Collapse failed to match node " ++ show k++-- | Rewrite the label of a given node.+updateNode :: DynGraph gr => (s -> s) -> Node -> gr s b -> gr s b+updateNode relabel node g = (preds, n, relabel this, succs) & g'+    where ((preds, n, this, succs), g') = forceMatch node g+++-- | Test if a graph has but a single node.+singletonGraph :: Graph gr => gr a b -> Bool+singletonGraph g = case labNodes g of [_] -> True+                                      _ -> False+++----------------  Supernodes ------------------------------------++-- | A "supernode" stands for a collection of one or more nodes (basic+-- blocks) that have been coalesced by the Hecht-Ullman algorithm.+-- A collection in a supernode constitutes a /reducible/ subgraph of a+-- control-flow graph.  (When an entire control-flow graph is collapsed+-- to a single supernode, the flow graph is reducible.)+--+-- The idea of node splitting is to collapse a control-flow graph down+-- to a single supernode, then materialize (``inflate'') the reducible+-- equivalent graph from that supernode.  The `Supernode` class+-- defines only the methods needed to collapse; rematerialization is+-- the responsiblity of the client.+--+-- During the Hecht-Ullman algorithm, every supernode has a unique+-- entry point, which is given by `superLabel`.  But this invariant is+-- not guaranteed by the class methods and is not a law of the class.+-- The `mapLabels` function rewrites all labels that appear in a+-- supernode (both definitions and uses).  The `freshen` function+-- replaces every appearance of a /defined/ label with a fresh label.+-- (Appearances include both definitions and uses.)+--+-- Laws:+-- @+--    superLabel (n <> n') == superLabel n+--    blocks (n <> n') == blocks n `union` blocks n'+--    mapLabels f (n <> n') = mapLabels f n <> mapLabels f n'+--    mapLabels id == id+--    mapLabels (f . g) == mapLabels f . mapLabels g+-- @+--+-- (We expect `freshen` to distribute over `<>`, but because of+-- the fresh names involved, formulating a precise law is a bit+-- challenging.)++class (Semigroup node) => PureSupernode node where+  superLabel :: node -> Label+  mapLabels :: (Label -> Label) -> (node -> node)++class (MonadUnique m, PureSupernode node) => Supernode node m where+  freshen :: node -> m node++  -- ghost method+  -- blocks :: node -> Set Block++------------------ Functions specific to the algorithm -----------------------++-- | Merge two nodes, return new graph plus list of nodes that newly have a single+-- predecessor.  This function implements transformation $T_2$ from+-- the Hecht and Ullman paper (merge the node into its unique+-- predecessor).  It then also removes self-edges (transformation $T_1$ from+-- the Hecht and Ullman paper).  There is no need for a separate+-- implementation of $T_1$.+--+-- `consumeBy v u g` returns the graph that results when node v is+-- consumed by node u in graph g.  Both v and u are replaced with a new node u'+-- with these properties:+--+--    LABELS(u') = LABELS(u) `union` LABELS(v)+--    SUCC(u') = SUCC(u) `union` SUCC(v) - { u }+--    every node that previously points to u now points to u'+--+-- It also returns a list of nodes in the result graph that+-- are *newly* single-predecessor nodes.++consumeBy :: (DynGraph gr, PureSupernode s)+          => Node -> Node -> gr s () -> (gr s (), [Node])+consumeBy toNode fromNode g =+    assert (toPreds == [((), fromNode)]) $+    (newGraph, newCandidates)+  where ((toPreds,   _, to,   toSuccs),   g')  = forceMatch toNode   g+        ((fromPreds, _, from, fromSuccs), g'') = forceMatch fromNode g'+        context = ( fromPreds -- by construction, can't have `toNode`+                  , fromNode+                  , from <> to+                  , delete ((), fromNode) toSuccs `union` fromSuccs+                  )+        newGraph = context & g''+        newCandidates = filter (singlePred newGraph) changedNodes+        changedNodes = fromNode `insert` map snd (toSuccs `intersect` fromSuccs)++-- | Split a given node.  The node is replaced with a collection of replicas,+-- one for each predecessor.  After the split, every predecessor+-- points to a unique replica.+split :: forall gr s b m . (DynGraph gr, Supernode s m)+      => Node -> gr s b -> m (gr s b)+split node g = assert (isMultiple preds) $ foldM addReplica g' newNodes+  where ((preds, _, this, succs), g') = forceMatch node g+        newNodes :: [((b, Node), Node)]+        newNodes = zip preds [maxNode+1..]+        (_, maxNode) = nodeRange g+        thisLabel = superLabel this+        addReplica :: gr s b -> ((b, Node), Node) -> m (gr s b)+        addReplica g ((b, pred), newNode) = do+            newSuper <- freshen this+            return $ add newSuper+          where add newSuper =+                  updateNode (thisLabel `replacedWith` superLabel newSuper) pred $+                  ([(b, pred)], newNode, newSuper, succs) & g++replacedWith :: PureSupernode s => Label -> Label -> s -> s+replacedWith old new = mapLabels (\l -> if l == old then new else l)+++-- | Does a list have more than one element? (in constant time).+isMultiple :: [a] -> Bool+isMultiple [] = False+isMultiple [_] = False+isMultiple (_:_:_) = True++-- | Find a candidate for splitting by finding a node that has multiple predecessors.++anySplittable :: forall gr a b . Graph gr => gr a b -> LNode a+anySplittable g = case splittable of+                    n : _ -> n+                    [] -> panic "anySplittable found no splittable nodes"+  where splittable = filter (isMultiple . pre g . fst) $ labNodes g+        splittable :: [LNode a]+++------------------ The collapsing algorithm -----------------------++-- | Using the algorithm of Hecht and Ullman (1972), collapse a graph+-- into a single node, splitting nodes as needed.  Record+-- visualization events in monad `m`.+collapseInductiveGraph :: (DynGraph gr, Supernode s m, VizCollapseMonad m gr s)+                       => gr s () -> m (gr s ())+collapseInductiveGraph g = drain g worklist+  where worklist :: [[Node]] -- nodes with exactly one predecessor+        worklist = [filter (singlePred g) $ nodes g]++        drain g [] = if singletonGraph g then finalGraph g >> return g+                     else let (n, super) = anySplittable g+                          in  do splitGraphAt g (n, super)+                                 collapseInductiveGraph =<< split n g+        drain g ([]:nss) = drain g nss+        drain g ((n:ns):nss) = let (g', ns') = consumeBy n (theUniquePred n) g+                               in  do consumeByInGraph n (theUniquePred n) g+                                      drain g' (ns':ns:nss)+         where theUniquePred n+                 | ([(_, p)], _, _, _) <- context g n = p+                 | otherwise =+                     panic "node claimed to have a unique predecessor; it doesn't"
compiler/GHC/Data/Graph/Color.hs view
@@ -328,8 +328,7 @@                         -- See Note [Unique Determinism and code generation]          colors_conflict = mkUniqSet-                        $ catMaybes-                        $ map nodeColor nsConflicts+                        $ mapMaybe nodeColor nsConflicts          -- the prefs of our neighbors         colors_neighbor_prefs
+ compiler/GHC/Data/Graph/Inductive/Graph.hs view
@@ -0,0 +1,643 @@+-- (c) 1999-2005 by Martin Erwig (see copyright at bottom)+-- | Static and Dynamic Inductive Graphs+--+-- Code is from Hackage `fgl` package version 5.7.0.3+--+module GHC.Data.Graph.Inductive.Graph (+    -- * General Type Defintions+    -- ** Node and Edge Types+    Node,LNode,UNode,+    Edge,LEdge,UEdge,+    -- ** Types Supporting Inductive Graph View+    Adj,Context,MContext,Decomp,GDecomp,UContext,UDecomp,+    Path,LPath(..),UPath,+    -- * Graph Type Classes+    -- | We define two graph classes:+    --+    --   Graph: static, decomposable graphs.+    --    Static means that a graph itself cannot be changed+    --+    --   DynGraph: dynamic, extensible graphs.+    --             Dynamic graphs inherit all operations from static graphs+    --             but also offer operations to extend and change graphs.+    --+    -- Each class contains in addition to its essential operations those+    -- derived operations that might be overwritten by a more efficient+    -- implementation in an instance definition.+    --+    -- Note that labNodes is essentially needed because the default definition+    -- for matchAny is based on it: we need some node from the graph to define+    -- matchAny in terms of match. Alternatively, we could have made matchAny+    -- essential and have labNodes defined in terms of ufold and matchAny.+    -- However, in general, labNodes seems to be (at least) as easy to define+    -- as matchAny. We have chosen labNodes instead of the function nodes since+    -- nodes can be easily derived from labNodes, but not vice versa.+    Graph(..),+    DynGraph(..),+    -- * Operations+    order,+    size,+    -- ** Graph Folds and Maps+    ufold,gmap,nmap,emap,nemap,+    -- ** Graph Projection+    nodes,edges,toEdge,edgeLabel,toLEdge,newNodes,gelem,+    -- ** Graph Construction and Destruction+    insNode,insEdge,delNode,delEdge,delLEdge,delAllLEdge,+    insNodes,insEdges,delNodes,delEdges,+    buildGr,mkUGraph,+    -- ** Subgraphs+    gfiltermap,nfilter,labnfilter,labfilter,subgraph,+    -- ** Graph Inspection+    context,lab,neighbors,lneighbors,+    suc,pre,lsuc,lpre,+    out,inn,outdeg,indeg,deg,+    hasEdge,hasNeighbor,hasLEdge,hasNeighborAdj,+    equal,+    -- ** Context Inspection+    node',lab',labNode',neighbors',lneighbors',+    suc',pre',lpre',lsuc',+    out',inn',outdeg',indeg',deg',+    -- * Pretty-printing+    prettify,+    prettyPrint,+    -- * Ordering of Graphs+    OrdGr(..)+) where++import GHC.Prelude++import           Control.Arrow (first)+import           Data.Function (on)+import qualified Data.IntSet   as IntSet+import           Data.List     (delete, groupBy, sort, sortBy, (\\))+import           Data.Maybe    (fromMaybe, isJust)++import GHC.Utils.Panic++-- | Unlabeled node+type  Node   = Int+-- | Labeled node+type LNode a = (Node,a)+-- | Quasi-unlabeled node+type UNode   = LNode ()++-- | Unlabeled edge+type  Edge   = (Node,Node)+-- | Labeled edge+type LEdge b = (Node,Node,b)+-- | Quasi-unlabeled edge+type UEdge   = LEdge ()++-- | Unlabeled path+type Path    = [Node]+-- | Labeled path+newtype LPath a = LP { unLPath :: [LNode a] }++instance (Show a) => Show (LPath a) where+  show (LP xs) = show xs++instance (Eq a) => Eq (LPath a) where+  (LP [])        == (LP [])        = True+  (LP ((_,x):_)) == (LP ((_,y):_)) = x==y+  (LP _)         == (LP _)         = False++instance (Ord a) => Ord (LPath a) where+  compare (LP [])        (LP [])        = EQ+  compare (LP ((_,x):_)) (LP ((_,y):_)) = compare x y+  compare _ _ = panic "LPath: cannot compare two empty paths"++-- | Quasi-unlabeled path+type UPath   = [UNode]++-- | Labeled links to or from a 'Node'.+type Adj b        = [(b,Node)]+-- | Links to the 'Node', the 'Node' itself, a label, links from the 'Node'.+--+--   In other words, this captures all information regarding the+--   specified 'Node' within a graph.+type Context a b  = (Adj b,Node,a,Adj b) -- Context a b "=" Context' a b "+" Node+type MContext a b = Maybe (Context a b)+-- | 'Graph' decomposition - the context removed from a 'Graph', and the rest+-- of the 'Graph'.+type Decomp g a b = (MContext a b,g a b)+-- | The same as 'Decomp', only more sure of itself.+type GDecomp g a b  = (Context a b,g a b)++-- | Unlabeled context.+type UContext     = ([Node],Node,[Node])+-- | Unlabeled decomposition.+type UDecomp g    = (Maybe UContext,g)++-- | Minimum implementation: 'empty', 'isEmpty', 'match', 'mkGraph', 'labNodes'+class Graph gr where+  {-# MINIMAL empty, isEmpty, match, mkGraph, labNodes #-}++  -- | An empty 'Graph'.+  empty     :: gr a b++  -- | True if the given 'Graph' is empty.+  isEmpty   :: gr a b -> Bool++  -- | Decompose a 'Graph' into the 'MContext' found for the given node and the+  -- remaining 'Graph'.+  match     :: Node -> gr a b -> Decomp gr a b++  -- | Create a 'Graph' from the list of 'LNode's and 'LEdge's.+  --+  --   For graphs that are also instances of 'DynGraph', @mkGraph ns+  --   es@ should be equivalent to @('insEdges' es . 'insNodes' ns)+  --   'empty'@.+  mkGraph   :: [LNode a] -> [LEdge b] -> gr a b++  -- | A list of all 'LNode's in the 'Graph'.+  labNodes  :: gr a b -> [LNode a]++  -- | Decompose a graph into the 'Context' for an arbitrarily-chosen 'Node'+  -- and the remaining 'Graph'.+  matchAny  :: gr a b -> GDecomp gr a b+  matchAny g = case labNodes g of+                 []      -> panic "Match Exception, Empty Graph"+                 (v,_):_ | (Just c,g') <- match v g -> (c,g')+                 _       -> panic "This can't happen: failed to match node in graph"+++  -- | The number of 'Node's in a 'Graph'.+  noNodes   :: gr a b -> Int+  noNodes = length . labNodes++  -- | The minimum and maximum 'Node' in a 'Graph'.+  nodeRange :: gr a b -> (Node,Node)+  nodeRange g+    | isEmpty g = panic "nodeRange of empty graph"+    | otherwise = (minimum vs, maximum vs)+    where+      vs = nodes g++  -- | A list of all 'LEdge's in the 'Graph'.+  labEdges  :: gr a b -> [LEdge b]+  labEdges = ufold (\(_,v,_,s)->(map (\(l,w)->(v,w,l)) s ++)) []++class (Graph gr) => DynGraph gr where+  -- | Merge the 'Context' into the 'DynGraph'.+  --+  --   Context adjacencies should only refer to either a Node already+  --   in a graph or the node in the Context itself (for loops).+  --+  --   Behaviour is undefined if the specified 'Node' already exists+  --   in the graph.+  (&) :: Context a b -> gr a b -> gr a b+++-- | The number of nodes in the graph.  An alias for 'noNodes'.+order :: (Graph gr) => gr a b -> Int+order = noNodes++-- | The number of edges in the graph.+--+--   Note that this counts every edge found, so if you are+--   representing an unordered graph by having each edge mirrored this+--   will be incorrect.+--+--   If you created an unordered graph by either mirroring every edge+--   (including loops!) or using the @undir@ function in+--   "Data.Graph.Inductive.Basic" then you can safely halve the value+--   returned by this.+size :: (Graph gr) => gr a b -> Int+size = length . labEdges++-- | Fold a function over the graph by recursively calling 'match'.+ufold :: (Graph gr) => (Context a b -> c -> c) -> c -> gr a b -> c+ufold f u g+  | isEmpty g = u+  | otherwise = f c (ufold f u g')+  where+    (c,g') = matchAny g++-- | Map a function over the graph by recursively calling 'match'.+gmap :: (DynGraph gr) => (Context a b -> Context c d) -> gr a b -> gr c d+gmap f = ufold (\c->(f c&)) empty+{-# NOINLINE [0] gmap #-}++-- | Map a function over the 'Node' labels in a graph.+nmap :: (DynGraph gr) => (a -> c) -> gr a b -> gr c b+nmap f = gmap (\(p,v,l,s)->(p,v,f l,s))+{-# NOINLINE [0] nmap #-}++-- | Map a function over the 'Edge' labels in a graph.+emap :: (DynGraph gr) => (b -> c) -> gr a b -> gr a c+emap f = gmap (\(p,v,l,s)->(map1 f p,v,l,map1 f s))+  where+    map1 g = map (first g)+{-# NOINLINE [0] emap #-}++-- | Map functions over both the 'Node' and 'Edge' labels in a graph.+nemap :: (DynGraph gr) => (a -> c) -> (b -> d) -> gr a b -> gr c d+nemap fn fe = gmap (\(p,v,l,s) -> (fe' p,v,fn l,fe' s))+  where+    fe' = map (first fe)+{-# NOINLINE [0] nemap #-}++-- | List all 'Node's in the 'Graph'.+nodes :: (Graph gr) => gr a b -> [Node]+nodes = map fst . labNodes++-- | List all 'Edge's in the 'Graph'.+edges :: (Graph gr) => gr a b -> [Edge]+edges = map toEdge . labEdges++-- | Drop the label component of an edge.+toEdge :: LEdge b -> Edge+toEdge (v,w,_) = (v,w)++-- | Add a label to an edge.+toLEdge :: Edge -> b -> LEdge b+toLEdge (v,w) l = (v,w,l)++-- | The label in an edge.+edgeLabel :: LEdge b -> b+edgeLabel (_,_,l) = l++-- | List N available 'Node's, i.e. 'Node's that are not used in the 'Graph'.+newNodes :: (Graph gr) => Int -> gr a b -> [Node]+newNodes i g+  | isEmpty g = [0..i-1]+  | otherwise = [n+1..n+i]+  where+    (_,n) = nodeRange g++-- | 'True' if the 'Node' is present in the 'Graph'.+gelem :: (Graph gr) => Node -> gr a b -> Bool+gelem v = isJust . fst . match v++-- | Insert a 'LNode' into the 'Graph'.+insNode :: (DynGraph gr) => LNode a -> gr a b -> gr a b+insNode (v,l) = (([],v,l,[])&)+{-# NOINLINE [0] insNode #-}++-- | Insert a 'LEdge' into the 'Graph'.+insEdge :: (DynGraph gr) => LEdge b -> gr a b -> gr a b+insEdge (v,w,l) g = (pr,v,la,(l,w):su) & g'+  where+    (mcxt,g') = match v g+    (pr,_,la,su) = fromMaybe+                     (panic ("insEdge: cannot add edge from non-existent vertex " ++ show v))+                     mcxt+{-# NOINLINE [0] insEdge #-}++-- | Remove a 'Node' from the 'Graph'.+delNode :: (Graph gr) => Node -> gr a b -> gr a b+delNode v = delNodes [v]++-- | Remove an 'Edge' from the 'Graph'.+--+--   NOTE: in the case of multiple edges, this will delete /all/ such+--   edges from the graph as there is no way to distinguish between+--   them.  If you need to delete only a single such edge, please use+--   'delLEdge'.+delEdge :: (DynGraph gr) => Edge -> gr a b -> gr a b+delEdge (v,w) g = case match v g of+                    (Nothing,_)          -> g+                    (Just (p,v',l,s),g') -> (p,v',l,filter ((/=w).snd) s) & g'++-- | Remove an 'LEdge' from the 'Graph'.+--+--   NOTE: in the case of multiple edges with the same label, this+--   will only delete the /first/ such edge.  To delete all such+--   edges, please use 'delAllLedge'.+delLEdge :: (DynGraph gr, Eq b) => LEdge b -> gr a b -> gr a b+delLEdge = delLEdgeBy delete++-- | Remove all edges equal to the one specified.+delAllLEdge :: (DynGraph gr, Eq b) => LEdge b -> gr a b -> gr a b+delAllLEdge = delLEdgeBy (filter . (/=))++delLEdgeBy :: (DynGraph gr) => ((b,Node) -> Adj b -> Adj b)+              -> LEdge b -> gr a b -> gr a b+delLEdgeBy f (v,w,b) g = case match v g of+                           (Nothing,_)          -> g+                           (Just (p,v',l,s),g') -> (p,v',l,f (b,w) s) & g'++-- | Insert multiple 'LNode's into the 'Graph'.+insNodes   :: (DynGraph gr) => [LNode a] -> gr a b -> gr a b+insNodes vs g = foldl' (flip insNode) g vs+{-# INLINABLE insNodes #-}++-- | Insert multiple 'LEdge's into the 'Graph'.+insEdges :: (DynGraph gr) => [LEdge b] -> gr a b -> gr a b+insEdges es g = foldl' (flip insEdge) g es+{-# INLINABLE insEdges #-}++-- | Remove multiple 'Node's from the 'Graph'.+delNodes :: (Graph gr) => [Node] -> gr a b -> gr a b+delNodes vs g = foldl' (snd .: flip match) g vs++-- | Remove multiple 'Edge's from the 'Graph'.+delEdges :: (DynGraph gr) => [Edge] -> gr a b -> gr a b+delEdges es g = foldl' (flip delEdge) g es++-- | Build a 'Graph' from a list of 'Context's.+--+--   The list should be in the order such that earlier 'Context's+--   depend upon later ones (i.e. as produced by @'ufold' (:) []@).+buildGr :: (DynGraph gr) => [Context a b] -> gr a b+buildGr = foldr (&) empty++-- | Build a quasi-unlabeled 'Graph'.+mkUGraph :: (Graph gr) => [Node] -> [Edge] -> gr () ()+mkUGraph vs es = mkGraph (labUNodes vs) (labUEdges es)+   where+     labUEdges = map (`toLEdge` ())+     labUNodes = map (flip (,) ())++-- | Build a graph out of the contexts for which the predicate is+-- satisfied by recursively calling 'match'.+gfiltermap :: DynGraph gr => (Context a b -> MContext c d) -> gr a b -> gr c d+gfiltermap f = ufold (maybe id (&) . f) empty++-- | Returns the subgraph only containing the labelled nodes which+-- satisfy the given predicate.+labnfilter :: Graph gr => (LNode a -> Bool) -> gr a b -> gr a b+labnfilter p gr = delNodes (map fst . filter (not . p) $ labNodes gr) gr++-- | Returns the subgraph only containing the nodes which satisfy the+-- given predicate.+nfilter :: DynGraph gr => (Node -> Bool) -> gr a b -> gr a b+nfilter f = labnfilter (f . fst)++-- | Returns the subgraph only containing the nodes whose labels+-- satisfy the given predicate.+labfilter :: DynGraph gr => (a -> Bool) -> gr a b -> gr a b+labfilter f = labnfilter (f . snd)++-- | Returns the subgraph induced by the supplied nodes.+subgraph :: DynGraph gr => [Node] -> gr a b -> gr a b+subgraph vs = let vs' = IntSet.fromList vs+              in nfilter (`IntSet.member` vs')++-- | Find the context for the given 'Node'.  Causes an error if the 'Node' is+-- not present in the 'Graph'.+context :: (Graph gr) => gr a b -> Node -> Context a b+context g v = fromMaybe (panic ("Match Exception, Node: "++show v))+                        (fst (match v g))++-- | Find the label for a 'Node'.+lab :: (Graph gr) => gr a b -> Node -> Maybe a+lab g v = fmap lab' . fst $ match v g++-- | Find the neighbors for a 'Node'.+neighbors :: (Graph gr) => gr a b -> Node -> [Node]+neighbors = map snd .: lneighbors++-- | Find the labelled links coming into or going from a 'Context'.+lneighbors :: (Graph gr) => gr a b -> Node -> Adj b+lneighbors = maybe [] lneighbors' .: mcontext++-- | Find all 'Node's that have a link from the given 'Node'.+suc :: (Graph gr) => gr a b -> Node -> [Node]+suc = map snd .: context4l++-- | Find all 'Node's that link to to the given 'Node'.+pre :: (Graph gr) => gr a b -> Node -> [Node]+pre = map snd .: context1l++-- | Find all 'Node's that are linked from the given 'Node' and the label of+-- each link.+lsuc :: (Graph gr) => gr a b -> Node -> [(Node,b)]+lsuc = map flip2 .: context4l++-- | Find all 'Node's that link to the given 'Node' and the label of each link.+lpre :: (Graph gr) => gr a b -> Node -> [(Node,b)]+lpre = map flip2 .: context1l++-- | Find all outward-bound 'LEdge's for the given 'Node'.+out :: (Graph gr) => gr a b -> Node -> [LEdge b]+out g v = map (\(l,w)->(v,w,l)) (context4l g v)++-- | Find all inward-bound 'LEdge's for the given 'Node'.+inn :: (Graph gr) => gr a b -> Node -> [LEdge b]+inn g v = map (\(l,w)->(w,v,l)) (context1l g v)++-- | The outward-bound degree of the 'Node'.+outdeg :: (Graph gr) => gr a b -> Node -> Int+outdeg = length .: context4l++-- | The inward-bound degree of the 'Node'.+indeg :: (Graph gr) => gr a b -> Node -> Int+indeg  = length .: context1l++-- | The degree of the 'Node'.+deg :: (Graph gr) => gr a b -> Node -> Int+deg = deg' .: context++-- | The 'Node' in a 'Context'.+node' :: Context a b -> Node+node' (_,v,_,_) = v++-- | The label in a 'Context'.+lab' :: Context a b -> a+lab' (_,_,l,_) = l++-- | The 'LNode' from a 'Context'.+labNode' :: Context a b -> LNode a+labNode' (_,v,l,_) = (v,l)++-- | All 'Node's linked to or from in a 'Context'.+neighbors' :: Context a b -> [Node]+neighbors' (p,_,_,s) = map snd p++map snd s++-- | All labelled links coming into or going from a 'Context'.+lneighbors' :: Context a b -> Adj b+lneighbors' (p,_,_,s) = p ++ s++-- | All 'Node's linked to in a 'Context'.+suc' :: Context a b -> [Node]+suc' = map snd . context4l'++-- | All 'Node's linked from in a 'Context'.+pre' :: Context a b -> [Node]+pre' = map snd . context1l'++-- | All 'Node's linked from in a 'Context', and the label of the links.+lsuc' :: Context a b -> [(Node,b)]+lsuc' = map flip2 . context4l'++-- | All 'Node's linked from in a 'Context', and the label of the links.+lpre' :: Context a b -> [(Node,b)]+lpre' = map flip2 . context1l'++-- | All outward-directed 'LEdge's in a 'Context'.+out' :: Context a b -> [LEdge b]+out' c@(_,v,_,_) = map (\(l,w)->(v,w,l)) (context4l' c)++-- | All inward-directed 'LEdge's in a 'Context'.+inn' :: Context a b -> [LEdge b]+inn' c@(_,v,_,_) = map (\(l,w)->(w,v,l)) (context1l' c)++-- | The outward degree of a 'Context'.+outdeg' :: Context a b -> Int+outdeg' = length . context4l'++-- | The inward degree of a 'Context'.+indeg' :: Context a b -> Int+indeg' = length . context1l'++-- | The degree of a 'Context'.+deg' :: Context a b -> Int+deg' (p,_,_,s) = length p+length s++-- | Checks if there is a directed edge between two nodes.+hasEdge :: Graph gr => gr a b -> Edge -> Bool+hasEdge gr (v,w) = w `elem` suc gr v++-- | Checks if there is an undirected edge between two nodes.+hasNeighbor :: Graph gr => gr a b -> Node -> Node -> Bool+hasNeighbor gr v w = w `elem` neighbors gr v++-- | Checks if there is a labelled edge between two nodes.+hasLEdge :: (Graph gr, Eq b) => gr a b -> LEdge b -> Bool+hasLEdge gr (v,w,l) = (w,l) `elem` lsuc gr v++-- | Checks if there is an undirected labelled edge between two nodes.+hasNeighborAdj :: (Graph gr, Eq b) => gr a b -> Node -> (b,Node) -> Bool+hasNeighborAdj gr v a = a `elem` lneighbors gr v++----------------------------------------------------------------------+-- GRAPH EQUALITY+----------------------------------------------------------------------++slabNodes :: (Graph gr) => gr a b -> [LNode a]+slabNodes = sortBy (compare `on` fst) . labNodes++glabEdges :: (Graph gr) => gr a b -> [GroupEdges b]+glabEdges = map (GEs . groupLabels)+            . groupBy ((==) `on` toEdge)+            . sortBy (compare `on` toEdge)+            . labEdges+  where+    groupLabels les = toLEdge (toEdge (head les)) (map edgeLabel les)++equal :: (Eq a,Eq b,Graph gr) => gr a b -> gr a b -> Bool+equal g g' = slabNodes g == slabNodes g' && glabEdges g == glabEdges g'+-- This assumes that nodes aren't repeated (which shouldn't happen for+-- sane graph instances).  If node IDs are repeated, then the usage of+-- slabNodes cannot guarantee stable ordering.++-- Newtype wrapper just to test for equality of multiple edges.  This+-- is needed because without an Ord constraint on `b' it is not+-- possible to guarantee a stable ordering on edge labels.+newtype GroupEdges b = GEs (LEdge [b])+  deriving (Show, Read)++instance (Eq b) => Eq (GroupEdges b) where+  (GEs (v1,w1,bs1)) == (GEs (v2,w2,bs2)) = v1 == v2+                                           && w1 == w2+                                           && eqLists bs1 bs2++eqLists :: (Eq a) => [a] -> [a] -> Bool+eqLists xs ys = null (xs \\ ys) && null (ys \\ xs)+-- OK to use \\ here as we want each value in xs to cancel a *single*+-- value in ys.++----------------------------------------------------------------------+-- UTILITIES+----------------------------------------------------------------------++-- auxiliary functions used in the implementation of the+-- derived class members+--+(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d+-- f .: g = \x y->f (g x y)+-- f .: g = (f .) . g+-- (.:) f = ((f .) .)+-- (.:) = (.) (.) (.)+(.:) = (.) . (.)++flip2 :: (a,b) -> (b,a)+flip2 (x,y) = (y,x)++-- projecting on context elements+--+context1l :: (Graph gr) => gr a b -> Node -> Adj b+context1l = maybe [] context1l' .: mcontext++context4l :: (Graph gr) => gr a b -> Node -> Adj b+context4l = maybe [] context4l' .: mcontext++mcontext :: (Graph gr) => gr a b -> Node -> MContext a b+mcontext = fst .: flip match++context1l' :: Context a b -> Adj b+context1l' (p,v,_,s) = p++filter ((==v).snd) s++context4l' :: Context a b -> Adj b+context4l' (p,v,_,s) = s++filter ((==v).snd) p++----------------------------------------------------------------------+-- PRETTY PRINTING+----------------------------------------------------------------------++-- | Pretty-print the graph.  Note that this loses a lot of+--   information, such as edge inverses, etc.+prettify :: (DynGraph gr, Show a, Show b) => gr a b -> String+prettify g = foldr (showsContext . context g) id (nodes g) ""+  where+    showsContext (_,n,l,s) sg = shows n . (':':) . shows l+                                . showString "->" . shows s+                                . ('\n':) . sg++-- | Pretty-print the graph to stdout.+prettyPrint :: (DynGraph gr, Show a, Show b) => gr a b -> IO ()+prettyPrint = putStr . prettify++----------------------------------------------------------------------+-- Ordered Graph+----------------------------------------------------------------------++-- | OrdGr comes equipped with an Ord instance, so that graphs can be+--   used as e.g. Map keys.+newtype OrdGr gr a b = OrdGr { unOrdGr :: gr a b }+  deriving (Read,Show)++instance (Graph gr, Ord a, Ord b) => Eq (OrdGr gr a b) where+  g1 == g2 = compare g1 g2 == EQ++instance (Graph gr, Ord a, Ord b) => Ord (OrdGr gr a b) where+  compare (OrdGr g1) (OrdGr g2) =+    (compare `on` sort . labNodes) g1 g2+    `mappend` (compare `on` sort . labEdges) g1 g2+++{-----------------------------------------------------------------++Copyright (c) 1999-2008, Martin Erwig+              2010, Ivan Lazar Miljenovic+              2022, Norman Ramsey+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice,+   this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+   notice, this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the distribution.++3. Neither the name of the author nor the names of its contributors may be+   used to endorse or promote products derived from this software without+   specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.++----------------------------------------------------------------}
+ compiler/GHC/Data/Graph/Inductive/PatriciaTree.hs view
@@ -0,0 +1,343 @@+{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}+{-# LANGUAGE DeriveGeneric #-}++-- |An efficient implementation of 'Data.Graph.Inductive.Graph.Graph'+-- using big-endian patricia tree (i.e. "Data.IntMap").+--+-- This module provides the following specialised functions to gain+-- more performance, using GHC's RULES pragma:+--+-- * 'Data.Graph.Inductive.Graph.insNode'+--+-- * 'Data.Graph.Inductive.Graph.insEdge'+--+-- * 'Data.Graph.Inductive.Graph.gmap'+--+-- * 'Data.Graph.Inductive.Graph.nmap'+--+-- * 'Data.Graph.Inductive.Graph.emap'+--+-- Code is from Hackage `fgl` package version 5.7.0.3+++module GHC.Data.Graph.Inductive.PatriciaTree+    ( Gr+    , UGr+    )+    where++import GHC.Prelude++import GHC.Data.Graph.Inductive.Graph++import           Data.IntMap         (IntMap)+import qualified Data.IntMap         as IM+import           Data.List           (sort)+import           Data.Maybe          (fromMaybe)+import           Data.Tuple          (swap)++import qualified Data.IntMap.Strict as IMS++import GHC.Generics (Generic)++import Data.Bifunctor++----------------------------------------------------------------------+-- GRAPH REPRESENTATION+----------------------------------------------------------------------++newtype Gr a b = Gr (GraphRep a b)+  deriving (Generic)++type GraphRep a b = IntMap (Context' a b)+type Context' a b = (IntMap [b], a, IntMap [b])++type UGr = Gr () ()++----------------------------------------------------------------------+-- CLASS INSTANCES+----------------------------------------------------------------------++instance (Eq a, Ord b) => Eq (Gr a b) where+  (Gr g1) == (Gr g2) = fmap sortAdj g1 == fmap sortAdj g2+    where+      sortAdj (p,n,s) = (fmap sort p,n,fmap sort s)++instance (Show a, Show b) => Show (Gr a b) where+  showsPrec d g = showParen (d > 10) $+                    showString "mkGraph "+                    . shows (labNodes g)+                    . showString " "+                    . shows (labEdges g)++instance (Read a, Read b) => Read (Gr a b) where+  readsPrec p = readParen (p > 10) $ \ r -> do+    ("mkGraph", s) <- lex r+    (ns,t) <- reads s+    (es,u) <- reads t+    return (mkGraph ns es, u)++instance Graph Gr where+    empty           = Gr IM.empty++    isEmpty (Gr g)  = IM.null g++    match           = matchGr++    mkGraph vs es   = insEdges es+                      . Gr+                      . IM.fromList+                      . map (second (\l -> (IM.empty,l,IM.empty)))+                      $ vs++    labNodes (Gr g) = [ (node, label)+                            | (node, (_, label, _)) <- IM.toList g ]++    noNodes   (Gr g) = IM.size g++    nodeRange (Gr g) = fromMaybe (error "nodeRange of empty graph")+                       $ liftA2 (,) (ix (IM.minViewWithKey g))+                                    (ix (IM.maxViewWithKey g))+      where+        ix = fmap (fst . fst)++    labEdges (Gr g) = do (node, (_, _, s)) <- IM.toList g+                         (next, labels)    <- IM.toList s+                         label             <- labels+                         return (node, next, label)++instance DynGraph Gr where+    (p, v, l, s) & (Gr g)+        = let !g1 = IM.insert v (preds, l, succs) g+              !(np, preds) = fromAdjCounting p+              !(ns, succs) = fromAdjCounting s+              !g2 = addSucc g1 v np preds+              !g3 = addPred g2 v ns succs+          in Gr g3+++instance Bifunctor Gr where+  bimap = fastNEMap++  first = fastNMap++  second = fastEMap+++matchGr :: Node -> Gr a b -> Decomp Gr a b+matchGr node (Gr g)+    = case IM.lookup node g of+        Nothing+            -> (Nothing, Gr g)++        Just (p, label, s)+            -> let !g1 = IM.delete node g+                   !p' = IM.delete node p+                   !s' = IM.delete node s+                   !g2 = clearPred g1 node s'+                   !g3 = clearSucc g2 node p'+               in (Just (toAdj p', node, label, toAdj s), Gr g3)++----------------------------------------------------------------------+-- OVERRIDING FUNCTIONS+----------------------------------------------------------------------++{-++{- RULES+      "insNode/Data.Graph.Inductive.PatriciaTree"  insNode = fastInsNode+  -}+fastInsNode :: LNode a -> Gr a b -> Gr a b+fastInsNode (v, l) (Gr g) = g' `seq` Gr g'+  where+    g' = IM.insert v (IM.empty, l, IM.empty) g++-}+{-# RULES+      "insEdge/GHC.Data.Graph.Inductive.PatriciaTree"  insEdge = fastInsEdge+  #-}+fastInsEdge :: LEdge b -> Gr a b -> Gr a b+fastInsEdge (v, w, l) (Gr g) = g2 `seq` Gr g2+  where+    g1 = IM.adjust addS' v g+    g2 = IM.adjust addP' w g1++    addS' (ps, l', ss) = (ps, l', IM.insertWith addLists w [l] ss)+    addP' (ps, l', ss) = (IM.insertWith addLists v [l] ps, l', ss)++{-++{- RULES+      "gmap/Data.Graph.Inductive.PatriciaTree"  gmap = fastGMap+  -}+fastGMap :: forall a b c d. (Context a b -> Context c d) -> Gr a b -> Gr c d+fastGMap f (Gr g) = Gr (IM.mapWithKey f' g)+  where+    f' :: Node -> Context' a b -> Context' c d+    f' = ((fromContext . f) .) . toContext++{- RULES+      "nmap/Data.Graph.Inductive.PatriciaTree"  nmap = fastNMap+  -}+-}+fastNMap :: forall a b c. (a -> c) -> Gr a b -> Gr c b+fastNMap f (Gr g) = Gr (IM.map f' g)+  where+    f' :: Context' a b -> Context' c b+    f' (ps, a, ss) = (ps, f a, ss)+{-++{- RULES+      "emap/GHC.Data.Graph.Inductive.PatriciaTree"  emap = fastEMap+   -}+-}+fastEMap :: forall a b c. (b -> c) -> Gr a b -> Gr a c+fastEMap f (Gr g) = Gr (IM.map f' g)+  where+    f' :: Context' a b -> Context' a c+    f' (ps, a, ss) = (IM.map (map f) ps, a, IM.map (map f) ss)++{-  RULES+      "nemap/GHC.Data.Graph.Inductive.PatriciaTree"  nemap = fastNEMap+   -}++fastNEMap :: forall a b c d. (a -> c) -> (b -> d) -> Gr a b -> Gr c d+fastNEMap fn fe (Gr g) = Gr (IM.map f g)+  where+    f :: Context' a b -> Context' c d+    f (ps, a, ss) = (IM.map (map fe) ps, fn a, IM.map (map fe) ss)++++----------------------------------------------------------------------+-- UTILITIES+----------------------------------------------------------------------++toAdj :: IntMap [b] -> Adj b+toAdj = concatMap expand . IM.toList+  where+    expand (n,ls) = map (flip (,) n) ls++--fromAdj :: Adj b -> IntMap [b]+--fromAdj = IM.fromListWith addLists . map (second (:[]) . swap)++data FromListCounting a = FromListCounting !Int !(IntMap a)+  deriving (Eq, Show, Read)++getFromListCounting :: FromListCounting a -> (Int, IntMap a)+getFromListCounting (FromListCounting i m) = (i, m)+{-# INLINE getFromListCounting #-}++fromListWithKeyCounting :: (Int -> a -> a -> a) -> [(Int, a)] -> (Int, IntMap a)+fromListWithKeyCounting f = getFromListCounting . foldl' ins (FromListCounting 0 IM.empty)+  where+    ins (FromListCounting i t) (k,x) = FromListCounting (i + 1) (IM.insertWithKey f k x t)+{-# INLINE fromListWithKeyCounting #-}++fromListWithCounting :: (a -> a -> a) -> [(Int, a)] -> (Int, IntMap a)+fromListWithCounting f = fromListWithKeyCounting (\_ x y -> f x y)+{-# INLINE fromListWithCounting #-}++fromAdjCounting :: Adj b -> (Int, IntMap [b])+fromAdjCounting = fromListWithCounting addLists . map (second (:[]) . swap)++-- We use differenceWith to modify a graph more than bulkThreshold times,+-- and repeated insertWith otherwise.+bulkThreshold :: Int+bulkThreshold = 5++--toContext :: Node -> Context' a b -> Context a b+--toContext v (ps, a, ss) = (toAdj ps, v, a, toAdj ss)++--fromContext :: Context a b -> Context' a b+--fromContext (ps, _, a, ss) = (fromAdj ps, a, fromAdj ss)++-- A version of @++@ where order isn't important, so @xs ++ [x]@+-- becomes @x:xs@.  Used when we have to have a function of type @[a]+-- -> [a] -> [a]@ but one of the lists is just going to be a single+-- element (and it isn't possible to tell which).+addLists :: [a] -> [a] -> [a]+addLists [a] as  = a : as+addLists as  [a] = a : as+addLists xs  ys  = xs ++ ys++addSucc :: forall a b . GraphRep a b -> Node -> Int -> IM.IntMap [b] -> GraphRep a b+addSucc g0 v numAdd xs+  | numAdd < bulkThreshold = foldlWithKey' go g0 xs+  where+    go :: GraphRep a b -> Node -> [b] -> GraphRep a b+    go g p l = IMS.adjust f p g+      where f (ps, l', ss) = let !ss' = IM.insertWith addLists v l ss+                             in (ps, l', ss')+addSucc g v _ xs = IMS.differenceWith go g xs+  where+    go :: Context' a b -> [b] -> Maybe (Context' a b)+    go (ps, l', ss) l = let !ss' = IM.insertWith addLists v l ss+                        in Just (ps, l', ss')++foldlWithKey' :: (a -> IM.Key -> b -> a) -> a -> IntMap b -> a+foldlWithKey' =+  IM.foldlWithKey'++addPred :: forall a b . GraphRep a b -> Node -> Int -> IM.IntMap [b] -> GraphRep a b+addPred g0 v numAdd xs+  | numAdd < bulkThreshold = foldlWithKey' go g0 xs+  where+    go :: GraphRep a b -> Node -> [b] -> GraphRep a b+    go g p l = IMS.adjust f p g+      where f (ps, l', ss) = let !ps' = IM.insertWith addLists v l ps+                             in (ps', l', ss)+addPred g v _ xs = IMS.differenceWith go g xs+  where+    go :: Context' a b -> [b] -> Maybe (Context' a b)+    go (ps, l', ss) l = let !ps' = IM.insertWith addLists v l ps+                        in Just (ps', l', ss)++clearSucc :: forall a b x . GraphRep a b -> Node -> IM.IntMap x -> GraphRep a b+clearSucc g v = IMS.differenceWith go g+  where+    go :: Context' a b -> x -> Maybe (Context' a b)+    go (ps, l, ss) _ = let !ss' = IM.delete v ss+                       in Just (ps, l, ss')++clearPred :: forall a b x . GraphRep a b -> Node -> IM.IntMap x -> GraphRep a b+clearPred g v = IMS.differenceWith go g+  where+    go :: Context' a b -> x -> Maybe (Context' a b)+    go (ps, l, ss) _ = let !ps' = IM.delete v ps+                       in Just (ps', l, ss)++{-----------------------------------------------------------------++Copyright (c) 1999-2008, Martin Erwig+              2010, Ivan Lazar Miljenovic+              2022, Norman Ramsey+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice,+   this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+   notice, this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the distribution.++3. Neither the name of the author nor the names of its contributors may be+   used to endorse or promote products derived from this software without+   specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.++----------------------------------------------------------------}
compiler/GHC/Data/Graph/Ops.hs view
@@ -633,7 +633,7 @@                                 $  nonDetEltsUniqSet $ nodeConflicts node             -- See Note [Unique Determinism and code generation] -        , neighbourColors       <- catMaybes $ map nodeColor neighbors+        , neighbourColors       <- mapMaybe nodeColor neighbors         , elem color neighbourColors         = False 
compiler/GHC/Driver/Backpack.hs view
@@ -597,7 +597,9 @@     mkUserStyle         (QueryQualify neverQualifyNames                       alwaysQualifyModules-                      neverQualifyPackages) AllTheWay+                      neverQualifyPackages+                      alwaysPrintPromTick)+        AllTheWay  -- | Message when we initially process a Backpack unit. msgTopPackage :: (Int,Int) -> HsComponentId -> BkpM ()@@ -939,4 +941,4 @@ newUnitId :: UnitId -> Maybe FastString -> UnitId newUnitId uid mhash = case mhash of    Nothing   -> uid-   Just hash -> UnitId (unitIdFS uid `appendFS` mkFastString "+" `appendFS` hash)+   Just hash -> UnitId (concatFS [unitIdFS uid, fsLit "+", hash])
compiler/GHC/Driver/CodeOutput.hs view
@@ -17,6 +17,7 @@ import GHC.Prelude import GHC.Platform import GHC.ForeignSrcLang+import GHC.Data.FastString  import GHC.CmmToAsm     ( nativeCodeGen ) import GHC.CmmToLlvm    ( llvmCodeGen )@@ -27,9 +28,9 @@ import GHC.Cmm.CLabel  import GHC.Driver.Session-import GHC.Driver.Config.Finder    (initFinderOpts)-import GHC.Driver.Config.CmmToAsm  (initNCGConfig)-import GHC.Driver.Config.CmmToLlvm (initLlvmCgConfig)+import GHC.Driver.Config.Finder    ( initFinderOpts   )+import GHC.Driver.Config.CmmToAsm  ( initNCGConfig    )+import GHC.Driver.Config.CmmToLlvm ( initLlvmCgConfig ) import GHC.Driver.LlvmConfigCache  (LlvmConfigCache) import GHC.Driver.Ppr import GHC.Driver.Backend@@ -44,8 +45,9 @@ import GHC.Utils.Error import GHC.Utils.Outputable import GHC.Utils.Logger-import GHC.Utils.Exception (bracket)+import GHC.Utils.Exception ( bracket ) import GHC.Utils.Ppr (Mode(..))+import GHC.Utils.Panic.Plain ( pgmError )  import GHC.Unit import GHC.Unit.Finder      ( mkStubPaths )@@ -124,6 +126,7 @@                                              final_stream                  ViaCCodeOutput -> outputC logger dflags filenm final_stream pkg_deps                  LlvmCodeOutput -> outputLlvm logger llvm_config dflags filenm final_stream+                 JSCodeOutput   -> outputJS logger llvm_config dflags filenm final_stream         ; stubs_exist <- outputForeignStubs logger tmpfs dflags unit_state this_mod location stubs         ; return (filenm, stubs_exist, foreign_fps, a)         }@@ -218,6 +221,18 @@ {- ************************************************************************ *                                                                      *+\subsection{JavaScript}+*                                                                      *+************************************************************************+-}+outputJS :: Logger -> LlvmConfigCache -> DynFlags -> FilePath -> Stream IO RawCmmGroup a -> IO a+outputJS _ _ _ _ _ = pgmError $ "codeOutput: Hit JavaScript case. We should never reach here!"+                              ++ "\nThe JS backend should shortcircuit to StgToJS after Stg."+                              ++ "\nIf you reached this point then you've somehow made it to Cmm!"++{-+************************************************************************+*                                                                      * \subsection{Foreign import/export} *                                                                      * ************************************************************************@@ -331,7 +346,7 @@    initializerCStub platform fn_name decls body  where    pdocC = pprCLabel platform-   fn_name = mkInitializerStubLabel this_mod "prof_init"+   fn_name = mkInitializerStubLabel this_mod (fsLit "prof_init")    decls = vcat         $  map emit_cc_decl local_CCs         ++ map emit_ccs_decl singleton_CCSs@@ -374,7 +389,7 @@   | not do_info_table = mempty   | otherwise = initializerCStub platform fn_nm ipe_buffer_decl body  where-   fn_nm = mkInitializerStubLabel this_mod "ip_init"+   fn_nm = mkInitializerStubLabel this_mod (fsLit "ip_init")     body = text "registerInfoProvList" <> parens (text "&" <> ipe_buffer_label) <> semi 
compiler/GHC/Driver/Config/Cmm.hs view
@@ -20,7 +20,8 @@   , cmmOptSink             = gopt Opt_CmmSink             dflags   , cmmGenStackUnwindInstr = debugLevel dflags > 0   , cmmExternalDynamicRefs = gopt Opt_ExternalDynamicRefs dflags-  , cmmDoCmmSwitchPlans    = not . backendHasNativeSwitch . backend $ dflags+  , cmmDoCmmSwitchPlans    = not (backendHasNativeSwitch (backend dflags))+                             || platformArch platform == ArchWasm32   , cmmSplitProcPoints     = not (backendSupportsUnsplitProcPoints (backend dflags))                              || not (platformTablesNextToCode platform)                              || usingInconsistentPicReg
compiler/GHC/Driver/Config/Core/Opt/Simplify.hs view
@@ -6,7 +6,7 @@  import GHC.Prelude -import GHC.Core ( RuleBase )+import GHC.Core.Rules ( RuleBase ) import GHC.Core.Opt.Pipeline.Types ( CoreToDo(..) ) import GHC.Core.Opt.Simplify ( SimplifyExprOpts(..), SimplifyOpts(..) ) import GHC.Core.Opt.Simplify.Env ( FloatEnable(..), SimplMode(..) )@@ -40,20 +40,19 @@   }  initSimplifyOpts :: DynFlags -> [Var] -> Int -> SimplMode -> RuleBase -> SimplifyOpts-initSimplifyOpts dflags extra_vars iterations mode rule_base = let+initSimplifyOpts dflags extra_vars iterations mode hpt_rule_base = let   -- This is a particularly ugly construction, but we will get rid of it in !8341.   opts = SimplifyOpts     { so_dump_core_sizes = not $ gopt Opt_SuppressCoreSizes dflags-    , so_iterations = iterations-    , so_mode = mode+    , so_iterations      = iterations+    , so_mode            = mode     , so_pass_result_cfg = if gopt Opt_DoCoreLinting dflags-      then Just $ initLintPassResultConfig dflags extra_vars (CoreDoSimplify opts)-      else Nothing-    , so_rule_base = rule_base-    , so_top_env_cfg = TopEnvConfig-        { te_history_size = historySize dflags-        , te_tick_factor = simplTickFactor dflags-        }+                           then Just $ initLintPassResultConfig dflags extra_vars+                                                            (CoreDoSimplify opts)+                           else Nothing+    , so_hpt_rules       = hpt_rule_base+    , so_top_env_cfg     = TopEnvConfig { te_history_size = historySize dflags+                                        , te_tick_factor = simplTickFactor dflags }     }   in opts 
compiler/GHC/Driver/Config/StgToCmm.hs view
@@ -2,6 +2,8 @@   ( initStgToCmmConfig   ) where +import GHC.Prelude.Basic+ import GHC.StgToCmm.Config  import GHC.Driver.Backend@@ -12,9 +14,6 @@ import GHC.Unit.Module import GHC.Utils.Outputable -import Data.Maybe-import Prelude- initStgToCmmConfig :: DynFlags -> Module -> StgToCmmConfig initStgToCmmConfig dflags mod = StgToCmmConfig   -- settings@@ -47,7 +46,7 @@   , stgToCmmDoBoundsCheck = gopt Opt_DoBoundsChecking      dflags   , stgToCmmDoTagCheck    = gopt Opt_DoTagInferenceChecks  dflags   -- backend flags-  , stgToCmmAllowBigArith             = not ncg+  , stgToCmmAllowBigArith             = not ncg || platformArch platform == ArchWasm32   , stgToCmmAllowQuotRemInstr         = ncg  && (x86ish || ppc)   , stgToCmmAllowQuotRem2             = (ncg && (x86ish || ppc)) || llvm   , stgToCmmAllowExtendedAddSubInstrs = (ncg && (x86ish || ppc)) || llvm@@ -64,8 +63,9 @@           b_blob  = if not ncg then Nothing else binBlobThreshold dflags           (ncg, llvm) = case backendPrimitiveImplementation bk_end of                           GenericPrimitives -> (False, False)-                          NcgPrimitives -> (True, False)-                          LlvmPrimitives -> (False, True)+                          JSPrimitives      -> (False, False)+                          NcgPrimitives     -> (True, False)+                          LlvmPrimitives    -> (False, True)           x86ish  = case platformArch platform of                       ArchX86    -> True                       ArchX86_64 -> True
+ compiler/GHC/Driver/Config/StgToJS.hs view
@@ -0,0 +1,32 @@+module GHC.Driver.Config.StgToJS+  ( initStgToJSConfig+  )+where++import GHC.StgToJS.Types++import GHC.Driver.Session+import GHC.Platform.Ways+import GHC.Utils.Outputable++import GHC.Prelude++-- | Initialize StgToJS settings from DynFlags+initStgToJSConfig :: DynFlags -> StgToJSConfig+initStgToJSConfig dflags = StgToJSConfig+  -- flags+  { csInlinePush      = False+  , csInlineBlackhole = False+  , csInlineLoadRegs  = False+  , csInlineEnter     = False+  , csInlineAlloc     = False+  , csTraceRts        = False+  , csAssertRts       = False+  , csBoundsCheck     = gopt Opt_DoBoundsChecking dflags+  , csDebugAlloc      = False+  , csTraceForeign    = False+  , csProf            = ways dflags `hasWay` WayProf+  , csRuntimeAssert   = False+  -- settings+  , csContext         = initSDocContext dflags defaultDumpStyle+  }
compiler/GHC/Driver/GenerateCgIPEStub.hs view
@@ -3,7 +3,7 @@ module GHC.Driver.GenerateCgIPEStub (generateCgIPEStub) where  import qualified Data.Map.Strict as Map-import Data.Maybe (catMaybes, listToMaybe)+import Data.Maybe (mapMaybe, listToMaybe) import GHC.Cmm import GHC.Cmm.CLabel (CLabel) import GHC.Cmm.Dataflow (Block, C, O)@@ -210,7 +210,7 @@     collectNothing _ cmmGroupSRTs = pure ([], cmmGroupSRTs)      collectInfoTables :: CmmGroupSRTs -> [(Label, CmmInfoTable)]-    collectInfoTables cmmGroup = concat $ catMaybes $ map extractInfoTables cmmGroup+    collectInfoTables cmmGroup = concat $ mapMaybe extractInfoTables cmmGroup      extractInfoTables :: GenCmmDecl RawCmmStatics CmmTopInfo CmmGraph -> Maybe [(Label, CmmInfoTable)]     extractInfoTables (CmmProc h _ _ _) = Just $ mapToList (info_tbls h)@@ -249,8 +249,7 @@          lastTickInBlock block =           listToMaybe $-            catMaybes $-              map maybeTick $ (reverse . blockToList) block+              mapMaybe maybeTick $ (reverse . blockToList) block          maybeTick :: CmmNode O O -> Maybe IpeSourceLocation         maybeTick (CmmTick (SourceNote span name)) = Just (span, name)
compiler/GHC/Driver/Main.hs view
@@ -132,6 +132,7 @@ import GHC.Driver.Config.StgToCmm  (initStgToCmmConfig) import GHC.Driver.Config.Cmm       (initCmmConfig) import GHC.Driver.LlvmConfigCache  (initLlvmConfigCache)+import GHC.Driver.Config.StgToJS  (initStgToJSConfig) import GHC.Driver.Config.Diagnostic import GHC.Driver.Config.Tidy import GHC.Driver.Hooks@@ -153,6 +154,7 @@ import GHC.HsToCore  import GHC.StgToByteCode    ( byteCodeGen )+import GHC.StgToJS          ( stgToJS )  import GHC.IfaceToCore  ( typecheckIface, typecheckWholeCoreBindings ) @@ -1789,7 +1791,9 @@                     cg_foreign  = foreign_stubs0,                     cg_foreign_files = foreign_files,                     cg_dep_pkgs = dependencies,-                    cg_hpc_info = hpc_info } = cgguts+                    cg_hpc_info = hpc_info,+                    cg_spt_entries = spt_entries+                    } = cgguts             dflags = hsc_dflags hsc_env             logger = hsc_logger hsc_env             hooks  = hsc_hooks hsc_env@@ -1849,40 +1853,55 @@         ------------------  Code generation ------------------         -- The back-end is streamed: each top-level function goes         -- from Stg all the way to asm before dealing with the next-        -- top-level function, so showPass isn't very useful here.-        -- Hence we have one showPass for the whole backend, the-        -- next showPass after this will be "Assembler".-        withTiming logger-                   (text "CodeGen"<+>brackets (ppr this_mod))-                   (const ()) $ do-            cmms <- {-# SCC "StgToCmm" #-}-                            doCodeGen hsc_env this_mod denv data_tycons-                                cost_centre_info-                                stg_binds hpc_info+        -- top-level function, so withTiming isn't very useful here.+        -- Hence we have one withTiming for the whole backend, the+        -- next withTiming after this will be "Assembler" (hard code only).+        withTiming logger (text "CodeGen"<+>brackets (ppr this_mod)) (const ())+         $ case backendCodeOutput (backend dflags) of+            JSCodeOutput ->+              do+              let js_config = initStgToJSConfig dflags+                  cmm_cg_infos  = Nothing+                  stub_c_exists = Nothing+                  foreign_fps   = [] -            ------------------  Code output ------------------------            rawcmms0 <- {-# SCC "cmmToRawCmm" #-}-                        case cmmToRawCmmHook hooks of-                            Nothing -> cmmToRawCmm logger profile cmms-                            Just h  -> h dflags (Just this_mod) cmms+              putDumpFileMaybe logger Opt_D_dump_stg_final "Final STG:" FormatSTG+                  (pprGenStgTopBindings (initStgPprOpts dflags) stg_binds) -            let dump a = do-                  unless (null a) $-                    putDumpFileMaybe logger Opt_D_dump_cmm_raw "Raw Cmm" FormatCMM (pdoc platform a)-                  return a-                rawcmms1 = Stream.mapM dump rawcmms0+              -- do the unfortunately effectual business+              stgToJS logger js_config stg_binds this_mod spt_entries foreign_stubs0 cost_centre_info output_filename+              return (output_filename, stub_c_exists, foreign_fps, Just stg_cg_infos, cmm_cg_infos) -            let foreign_stubs st = foreign_stubs0 `appendStubC` prof_init-                                                  `appendStubC` cgIPEStub st+            _          ->+              do+              cmms <- {-# SCC "StgToCmm" #-}+                doCodeGen hsc_env this_mod denv data_tycons+                cost_centre_info+                stg_binds hpc_info -            (output_filename, (_stub_h_exists, stub_c_exists), foreign_fps, cmm_cg_infos)-                <- {-# SCC "codeOutput" #-}-                  codeOutput logger tmpfs llvm_config dflags (hsc_units hsc_env) this_mod output_filename location-                  foreign_stubs foreign_files dependencies rawcmms1-            return  ( output_filename, stub_c_exists, foreign_fps-                    , Just stg_cg_infos, Just cmm_cg_infos)+              ------------------  Code output -----------------------+              rawcmms0 <- {-# SCC "cmmToRawCmm" #-}+                case cmmToRawCmmHook hooks of+                  Nothing -> cmmToRawCmm logger profile cmms+                  Just h  -> h dflags (Just this_mod) cmms +              let dump a = do+                    unless (null a) $ putDumpFileMaybe logger Opt_D_dump_cmm_raw "Raw Cmm" FormatCMM (pdoc platform a)+                    return a+                  rawcmms1 = Stream.mapM dump rawcmms0 +              let foreign_stubs st = foreign_stubs0+                                     `appendStubC` prof_init+                                     `appendStubC` cgIPEStub st++              (output_filename, (_stub_h_exists, stub_c_exists), foreign_fps, cmm_cg_infos)+                  <- {-# SCC "codeOutput" #-}+                    codeOutput logger tmpfs llvm_config dflags (hsc_units hsc_env) this_mod output_filename location+                    foreign_stubs foreign_files dependencies rawcmms1+              return  ( output_filename, stub_c_exists, foreign_fps+                      , Just stg_cg_infos, Just cmm_cg_infos)++ -- The part of CgGuts that we need for HscInteractive data CgInteractiveGuts = CgInteractiveGuts { cgi_module :: Module                                            , cgi_binds  :: CoreProgram@@ -2120,7 +2139,7 @@        binding for the stg2stg step) -}     let bco_tmp_id = mkSysLocal (fsLit "BCO_toplevel")                                 (mkPseudoUniqueE 0)-                                Many+                                ManyTy                                 (exprType prepd_expr)     (stg_binds, prov_map, collected_ccs, stg_cg_infos) <-        myCoreToStg logger@@ -2473,9 +2492,10 @@   -- post tidy pretty-printing and linting...   let tidy_rules     = md_rules details   let all_tidy_binds = cg_binds cgguts-  let print_unqual   = mkPrintUnqualified (hsc_unit_env hsc_env) (mg_rdr_env guts)+  let name_ppr_ctx   = mkNamePprCtx ptc (hsc_unit_env hsc_env) (mg_rdr_env guts)+      ptc            = initPromotionTickContext (hsc_dflags hsc_env) -  endPassHscEnvIO hsc_env print_unqual CoreTidy all_tidy_binds tidy_rules+  endPassHscEnvIO hsc_env name_ppr_ctx CoreTidy all_tidy_binds tidy_rules    -- If the endPass didn't print the rules, but ddump-rules is   -- on, print now
compiler/GHC/Driver/Make.hs view
@@ -5,7 +5,6 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-}@@ -741,8 +740,8 @@                     Just n  -> return n      setSession $ hscUpdateHUG (unitEnv_map pruneHomeUnitEnv) hsc_env-    hsc_env <- getSession-    (upsweep_ok, hsc_env1) <- withDeferredDiagnostics $+    (upsweep_ok, hsc_env1) <- withDeferredDiagnostics $ do+      hsc_env <- getSession       liftIO $ upsweep n_jobs hsc_env mhmi_cache mHscMessage (toCache pruned_cache) build_plan     setSession hsc_env1     case upsweep_ok of
compiler/GHC/Driver/Pipeline.hs view
@@ -42,7 +42,7 @@    TPipelineClass, MonadUse(..),     preprocessPipeline, fullPipeline, hscPipeline, hscBackendPipeline, hscPostBackendPipeline,-   hscGenBackendPipeline, asPipeline, viaCPipeline, cmmCppPipeline, cmmPipeline,+   hscGenBackendPipeline, asPipeline, viaCPipeline, cmmCppPipeline, cmmPipeline, jsPipeline,    llvmPipeline, llvmLlcPipeline, llvmManglePipeline, pipelineStart,     -- * Default method of running a pipeline@@ -62,6 +62,7 @@ import GHC.Driver.Errors.Types import GHC.Driver.Pipeline.Monad import GHC.Driver.Config.Diagnostic+import GHC.Driver.Config.StgToJS import GHC.Driver.Phases import GHC.Driver.Pipeline.Execute import GHC.Driver.Pipeline.Phases@@ -81,6 +82,9 @@ import GHC.Linker.Static.Utils import GHC.Linker.Types +import GHC.StgToJS.Linker.Linker+import GHC.StgToJS.Linker.Types (defaultJSLinkConfig)+ import GHC.Utils.Outputable import GHC.Utils.Error import GHC.Utils.Panic@@ -364,17 +368,17 @@ link ghcLink logger tmpfs hooks dflags unit_env batch_attempt_linking mHscMessage hpt =   case linkHook hooks of       Nothing -> case ghcLink of-          NoLink        -> return Succeeded-          LinkBinary    -> normal_link-          LinkStaticLib -> normal_link-          LinkDynLib    -> normal_link-          LinkMergedObj -> normal_link-          LinkInMemory-              | platformMisc_ghcWithInterpreter $ platformMisc dflags-              -> -- Not Linking...(demand linker will do the job)-                 return Succeeded-              | otherwise-              -> panicBadLink LinkInMemory+        NoLink        -> return Succeeded+        LinkBinary    -> normal_link+        LinkStaticLib -> normal_link+        LinkDynLib    -> normal_link+        LinkMergedObj -> normal_link+        LinkInMemory+          | platformMisc_ghcWithInterpreter $ platformMisc dflags+           -- Not Linking...(demand linker will do the job)+            -> return Succeeded+          | otherwise+            -> panicBadLink LinkInMemory       Just h  -> h ghcLink dflags batch_attempt_linking hpt   where     normal_link = link' logger tmpfs dflags unit_env batch_attempt_linking mHscMessage hpt@@ -412,7 +416,9 @@             -- the linkables to link             linkables = map (expectJust "link". homeModInfoObject) home_mod_infos +        debugTraceMsg logger 3 (text "link: hmi ..." $$ vcat (map (ppr . mi_module . hm_iface) home_mod_infos))         debugTraceMsg logger 3 (text "link: linkables are ..." $$ vcat (map ppr linkables))+        debugTraceMsg logger 3 (text "link: pkg deps are ..." $$ vcat (map ppr pkg_deps))          -- check for the -no-link flag         if isNoLink (ghcLink dflags)@@ -423,7 +429,8 @@         let getOfiles LM{ linkableUnlinked } = map nameOfObject (filter isObject linkableUnlinked)             obj_files = concatMap getOfiles linkables             platform  = targetPlatform dflags-            exe_file  = exeFileName platform staticLink (outputFile_ dflags)+            arch_os   = platformArchOS platform+            exe_file  = exeFileName arch_os staticLink (outputFile_ dflags)          linking_needed <- linkingNeeded logger dflags unit_env staticLink linkables pkg_deps @@ -435,12 +442,13 @@           -- Don't showPass in Batch mode; doLink will do that for us.-        let link = case ghcLink dflags of-                LinkBinary    -> linkBinary logger tmpfs-                LinkStaticLib -> linkStaticLib logger-                LinkDynLib    -> linkDynLibCheck logger tmpfs-                other         -> panicBadLink other-        link dflags unit_env obj_files pkg_deps+        case ghcLink dflags of+          LinkBinary+            | backendUseJSLinker (backend dflags) -> linkJSBinary logger dflags unit_env obj_files pkg_deps+            | otherwise -> linkBinary logger tmpfs dflags unit_env obj_files pkg_deps+          LinkStaticLib -> linkStaticLib logger dflags unit_env obj_files pkg_deps+          LinkDynLib    -> linkDynLibCheck logger tmpfs dflags unit_env obj_files pkg_deps+          other         -> panicBadLink other          debugTraceMsg logger 3 (text "link: done") @@ -453,6 +461,15 @@         return Succeeded  +linkJSBinary :: Logger -> DynFlags -> UnitEnv -> [FilePath] -> [UnitId] -> IO ()+linkJSBinary logger dflags unit_env obj_files pkg_deps = do+  -- we use the default configuration for now. In the future we may expose+  -- settings to the user via DynFlags.+  let lc_cfg   = defaultJSLinkConfig+  let cfg      = initStgToJSConfig dflags+  let extra_js = mempty+  jsLinkBinary lc_cfg cfg extra_js logger dflags unit_env obj_files pkg_deps+ linkingNeeded :: Logger -> DynFlags -> UnitEnv -> Bool -> [Linkable] -> [UnitId] -> IO RecompileRequired linkingNeeded logger dflags unit_env staticLink linkables pkg_deps = do         -- if the modification time on the executable is later than the@@ -460,7 +477,8 @@         -- linking (unless the -fforce-recomp flag was given).   let platform   = ue_platform unit_env       unit_state = ue_units unit_env-      exe_file   = exeFileName platform staticLink (outputFile_ dflags)+      arch_os    = platformArchOS platform+      exe_file   = exeFileName arch_os staticLink (outputFile_ dflags)   e_exe_time <- tryIO $ getModificationUTCTime exe_file   case e_exe_time of     Left _  -> return $ NeedsRecompile MustCompile@@ -544,24 +562,28 @@   doLink :: HscEnv -> [FilePath] -> IO ()-doLink hsc_env o_files =-    let-        dflags   = hsc_dflags   hsc_env-        logger   = hsc_logger   hsc_env-        unit_env = hsc_unit_env hsc_env-        tmpfs    = hsc_tmpfs    hsc_env-    in case ghcLink dflags of-        NoLink        -> return ()-        LinkBinary    -> linkBinary         logger tmpfs dflags unit_env o_files []-        LinkStaticLib -> linkStaticLib      logger       dflags unit_env o_files []-        LinkDynLib    -> linkDynLibCheck    logger tmpfs dflags unit_env o_files []-        LinkMergedObj-          | Just out <- outputFile dflags-          , let objs = [ f | FileOption _ f <- ldInputs dflags ]-                      -> joinObjectFiles hsc_env (o_files ++ objs) out-          | otherwise -> panic "Output path must be specified for LinkMergedObj"-        other         -> panicBadLink other+doLink hsc_env o_files = do+  let+    dflags   = hsc_dflags   hsc_env+    logger   = hsc_logger   hsc_env+    unit_env = hsc_unit_env hsc_env+    tmpfs    = hsc_tmpfs    hsc_env +  case ghcLink dflags of+    NoLink        -> return ()+    LinkBinary+      | backendUseJSLinker (backend dflags)+                  -> linkJSBinary logger dflags unit_env o_files []+      | otherwise -> linkBinary logger tmpfs dflags unit_env o_files []+    LinkStaticLib -> linkStaticLib      logger       dflags unit_env o_files []+    LinkDynLib    -> linkDynLibCheck    logger tmpfs dflags unit_env o_files []+    LinkMergedObj+      | Just out <- outputFile dflags+      , let objs = [ f | FileOption _ f <- ldInputs dflags ]+                  -> joinObjectFiles hsc_env (o_files ++ objs) out+      | otherwise -> panic "Output path must be specified for LinkMergedObj"+    other         -> panicBadLink other+ ----------------------------------------------------------------------------- -- stub .h and .c files (for foreign export support), and cc files. @@ -585,6 +607,7 @@               LangObjc   -> viaCPipeline Cobjc               LangObjcxx -> viaCPipeline Cobjcxx               LangAsm    -> \pe hsc_env ml fp -> asPipeline True pe hsc_env ml fp+              LangJs     -> \pe hsc_env ml fp -> Just <$> jsPipeline pe hsc_env ml fp #if __GLASGOW_HASKELL__ < 811               RawObject  -> panic "compileForeign: should be unreachable" #endif@@ -608,16 +631,29 @@   -- and https://github.com/haskell/cabal/issues/2257   let logger = hsc_logger hsc_env   let tmpfs  = hsc_tmpfs hsc_env-  empty_stub <- newTempName logger tmpfs (tmpDir dflags) TFL_CurrentModule "c"   let home_unit = hsc_home_unit hsc_env-      src = text "int" <+> ppr (mkHomeModule home_unit mod_name) <+> text "= 0;"-  writeFile empty_stub (showSDoc dflags (pprCode src))-  let pipe_env = (mkPipeEnv NoStop empty_stub Nothing Persistent) { src_basename = basename}-      pipeline = viaCPipeline HCc pipe_env hsc_env (Just location) empty_stub-  _ <- runPipeline (hsc_hooks hsc_env) pipeline-  return () +  case backendCodeOutput (backend dflags) of+    JSCodeOutput -> do+      empty_stub <- newTempName logger tmpfs (tmpDir dflags) TFL_CurrentModule "js"+      let src = ppr (mkHomeModule home_unit mod_name) <+> text "= 0;"+      writeFile empty_stub (showSDoc dflags (pprCode src))+      let pipe_env = (mkPipeEnv NoStop empty_stub Nothing Persistent) { src_basename = basename}+          pipeline = Just <$> jsPipeline pipe_env hsc_env (Just location) empty_stub+      _ <- runPipeline (hsc_hooks hsc_env) pipeline+      pure () +    _ -> do+      empty_stub <- newTempName logger tmpfs (tmpDir dflags) TFL_CurrentModule "c"+      let src = text "int" <+> ppr (mkHomeModule home_unit mod_name) <+> text "= 0;"+      writeFile empty_stub (showSDoc dflags (pprCode src))+      let pipe_env = (mkPipeEnv NoStop empty_stub Nothing Persistent) { src_basename = basename}+          pipeline = viaCPipeline HCc pipe_env hsc_env (Just location) empty_stub+      _ <- runPipeline (hsc_hooks hsc_env) pipeline+      pure ()+++ {- Environment Initialisation -}  mkPipeEnv :: StopPhase -- End phase@@ -818,6 +854,10 @@     Nothing -> panic "CMM pipeline - produced no .o file"     Just mo_fn -> use (T_MergeForeign pipe_env hsc_env mo_fn fos) +jsPipeline :: P m => PipeEnv -> HscEnv -> Maybe ModLocation -> FilePath -> m FilePath+jsPipeline pipe_env hsc_env location input_fn = do+  use (T_Js pipe_env hsc_env location input_fn)+ hscPostBackendPipeline :: P m => PipeEnv -> HscEnv -> HscSource -> Backend -> Maybe ModLocation -> FilePath -> m (Maybe FilePath) hscPostBackendPipeline _ _ HsBootFile _ _ _   = return Nothing hscPostBackendPipeline _ _ HsigFile _ _ _     = return Nothing@@ -833,9 +873,10 @@ applyPostHscPipeline ViaCPostHscPipeline = viaCPipeline HCc applyPostHscPipeline LlvmPostHscPipeline =     \pe he ml fp -> llvmPipeline pe he ml fp+applyPostHscPipeline JSPostHscPipeline =+    \pe he ml fp -> Just <$> jsPipeline pe he ml fp applyPostHscPipeline NoPostHscPipeline = \_ _ _ _ -> return Nothing - -- Pipeline from a given suffix pipelineStart :: P m => PipeEnv -> HscEnv -> FilePath -> Maybe Phase -> m (Maybe FilePath) pipelineStart pipe_env hsc_env input_fn mb_phase =@@ -870,7 +911,6 @@    objFromLinkable (_, homeMod_object -> Just (LM _ _ [DotO lnk])) = Just lnk    objFromLinkable _ = Nothing -    fromPhase :: P m => Phase -> m (Maybe FilePath)    fromPhase (Unlit p)  = frontend p    fromPhase (Cpp p)    = frontend p@@ -888,6 +928,7 @@    fromPhase StopLn     = return (Just input_fn)    fromPhase CmmCpp     = Just <$> cmmCppPipeline pipe_env hsc_env input_fn    fromPhase Cmm        = Just <$> cmmPipeline pipe_env hsc_env input_fn+   fromPhase Js         = Just <$> jsPipeline pipe_env hsc_env Nothing input_fn    fromPhase MergeForeign = panic "fromPhase: MergeForeign"  {-
compiler/GHC/Driver/Pipeline/Execute.hs view
@@ -46,6 +46,7 @@ import Data.Maybe import GHC.CmmToLlvm.Mangler import GHC.SysTools+import GHC.SysTools.Cpp import GHC.Utils.Panic.Plain import System.Directory import System.FilePath@@ -72,13 +73,12 @@ import System.IO import GHC.Linker.ExtraObj import GHC.Linker.Dynamic-import Data.Version import GHC.Utils.Panic import GHC.Unit.Module.Env import GHC.Driver.Env.KnotVars import GHC.Driver.Config.Finder import GHC.Rename.Names-import GHC.SysTools.Cpp+import GHC.StgToJS.Linker.Linker (embedJsFile)  import Language.Haskell.Syntax.Module.Name import GHC.Unit.Home.ModInfo@@ -127,6 +127,7 @@           })         input_fn output_fn   return output_fn+runPhase (T_Js pipe_env hsc_env _mb_location js_src) = runJsPhase pipe_env hsc_env js_src runPhase (T_Cmm pipe_env hsc_env input_fn) = do   let dflags = hsc_dflags hsc_env   let next_phase = hscPostBackendPhase HsSrcFile (backend dflags)@@ -323,6 +324,10 @@                           , not $ target32Bit (targetPlatform dflags)                           ] +                       -- See Note [-Wa,--no-type-check on wasm32]+                       ++ [ GHC.SysTools.Option "-Wa,--no-type-check"+                          | platformArch (targetPlatform dflags) == ArchWasm32]+                        ++ (if any (asmInfo ==) [Clang, AppleClang, AppleClang51]                             then [GHC.SysTools.Option "-Qunused-arguments"]                             else [])@@ -341,11 +346,62 @@          return output_fn ++-- Note [JS Backend .o file procedure]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- The JS backend breaks some of the assumptions on file generation order+-- because it directly produces .o files. This violation breaks some of the+-- assumptions on file timestamps, particularly in the postHsc phase. The+-- postHsc phase for the JS backend is performed in 'runJsPhase'. Consider+-- what the NCG does:+--+-- With other NCG backends we have the following order:+-- 1. The backend produces a .s file+-- 2. Then we write the interface file, .hi+-- 3. Then we generate a .o file in a postHsc phase (calling the asm phase etc.)+--+-- For the JS Backend this order is different+-- 1. The JS Backend _directly_ produces .o files+-- 2. Then we write the interface file. Notice that this breaks the ordering+-- of .hi > .o (step 2 and step 3 in the NCG above).+--+-- This violation results in timestamp checks which pass on the NCG but fail+-- in the JS backend. In particular, checks that compare 'ms_obj_date', and+-- 'ms_iface_date' in 'GHC.Unit.Module.ModSummary'.+--+-- Thus to fix this ordering we touch the object files we generated earlier+-- to ensure these timestamps abide by the proper ordering.++-- | Run the JS Backend postHsc phase.+runJsPhase :: PipeEnv -> HscEnv -> FilePath -> IO FilePath+runJsPhase pipe_env hsc_env input_fn = do+  let dflags     = hsc_dflags   hsc_env+  let logger     = hsc_logger   hsc_env+  let tmpfs      = hsc_tmpfs    hsc_env+  let unit_env   = hsc_unit_env hsc_env++  output_fn <- phaseOutputFilenameNew StopLn pipe_env hsc_env Nothing++  -- if the input filename is the same as the output, then we've probably+  -- generated the object ourselves. In this case, we touch the object file to+  -- ensure the timestamp is refreshed, see Note [JS Backend .o file procedure]. If+  -- they are not the same then we embed the .js file into a .o file with the+  -- addition of a header+  if (input_fn /= output_fn)+    then embedJsFile logger dflags tmpfs unit_env input_fn output_fn+    else touchObjectFile logger dflags output_fn++  return output_fn++ applyAssemblerInfoGetter     :: DefunctionalizedAssemblerInfoGetter     -> Logger -> DynFlags -> Platform -> IO CompilerInfo applyAssemblerInfoGetter StandardAssemblerInfoGetter logger dflags _platform =     getAssemblerInfo logger dflags+applyAssemblerInfoGetter JSAssemblerInfoGetter _ _ _ =+    pure Emscripten applyAssemblerInfoGetter DarwinClangAssemblerInfoGetter logger dflags platform =     if platformOS platform == OSDarwin then         pure Clang@@ -357,6 +413,8 @@     -> Logger -> DynFlags -> Platform -> [Option] -> IO () applyAssemblerProg StandardAssemblerProg logger dflags _platform =     runAs logger dflags+applyAssemblerProg JSAssemblerProg logger dflags _platform =+    runEmscripten logger dflags applyAssemblerProg DarwinClangAssemblerProg logger dflags platform =     if platformOS platform == OSDarwin then         runClang logger dflags@@ -1109,36 +1167,6 @@   --- ------------------------------------------------------------------------------ Macros (cribbed from Cabal)--generatePackageVersionMacros :: [UnitInfo] -> String-generatePackageVersionMacros pkgs = concat-  -- Do not add any C-style comments. See #3389.-  [ generateMacros "" pkgname version-  | pkg <- pkgs-  , let version = unitPackageVersion pkg-        pkgname = map fixchar (unitPackageNameString pkg)-  ]--fixchar :: Char -> Char-fixchar '-' = '_'-fixchar c   = c--generateMacros :: String -> String -> Version -> String-generateMacros prefix name version =-  concat-  ["#define ", prefix, "VERSION_",name," ",show (showVersion version),"\n"-  ,"#define MIN_", prefix, "VERSION_",name,"(major1,major2,minor) (\\\n"-  ,"  (major1) <  ",major1," || \\\n"-  ,"  (major1) == ",major1," && (major2) <  ",major2," || \\\n"-  ,"  (major1) == ",major1," && (major2) == ",major2," && (minor) <= ",minor,")"-  ,"\n\n"-  ]-  where-    (major1:major2:minor:_) = map show (versionBranch version ++ repeat 0)-- -- ----------------------------------------------------------------------------- -- Misc. @@ -1246,4 +1274,31 @@   that commit was addressing has since been solved in a different manner, in a   commit called "Fix the filename passed to unlit" (1eedbc6b). So the   `normalise` is no longer necessary.+-}++{-+Note [-Wa,--no-type-check on wasm32]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Wasm32 has a type system and corresponding validation rules, so it's+possible to produce syntactically valid object code that doesn't pass+validation.++We have no problem with that, but we do have a problem with clang.+When clang takes an assembly input for wasm32, it uses its internal+type-checker, which is a huge source of trouble (see llvm ticket+#56935 #58438): it may reject valid assembly, and even worse, it may+silently alter the output object code!!! The worsest of all, is the+person that added the wasm32 asm typechecker logic has moved on from+Google/LLVM, and while other LLVM devs may be knowledgable enough to+fix this mess, they likely got tons of other stuff on their table and+don't care enough.++We do have an escape hatch, just pass -Wa,--no-type-check to clang to+bypass the entire wasm32 asm typechecking logic. There's little point+in type-checking object code at compile-time anyway, the wasm engines+will do type-checking at run-time. And even if we want to add some+linting flag to do compile-time checks, we should just rely on+battle-tested external tools instead of a completely broken horror+story. -}
compiler/GHC/Hs/Syn/Type.hs view
@@ -21,10 +21,10 @@ import GHC.Core.PatSyn import GHC.Core.TyCo.Rep import GHC.Core.Type-import GHC.Core.Utils import GHC.Hs import GHC.Tc.Types.Evidence import GHC.Types.Id+import GHC.Types.Var( VarBndr(..) ) import GHC.Types.SrcLoc import GHC.Utils.Outputable import GHC.Utils.Panic@@ -182,9 +182,9 @@           exp_res = hsWrapperType w2 act_res       in mkFunctionType m exp_arg exp_res     go (WpCast co)        = liftPRType $ \_ -> coercionRKind co-    go (WpEvLam v)        = liftPRType $ mkInvisFunTyMany (idType v)+    go (WpEvLam v)        = liftPRType $ mkInvisFunTy (idType v)     go (WpEvApp _)        = liftPRType $ funResultTy-    go (WpTyLam tv)       = liftPRType $ mkForAllTy tv Inferred+    go (WpTyLam tv)       = liftPRType $ mkForAllTy (Bndr tv Inferred)     go (WpTyApp ta)       = \(ty,tas) -> (ty, ta:tas)     go (WpLet _)          = id     go (WpMultCoercion _) = id@@ -193,7 +193,7 @@ lhsCmdTopType (L _ (HsCmdTop (CmdTopTc _ ret_ty _) _)) = ret_ty  matchGroupTcType :: MatchGroupTc -> Type-matchGroupTcType (MatchGroupTc args res _) = mkVisFunTys args res+matchGroupTcType (MatchGroupTc args res _) = mkScaledFunTys args res  syntaxExprType :: SyntaxExpr GhcTc -> Type syntaxExprType (SyntaxExprTc e _ _) = hsExprType e
compiler/GHC/HsToCore.hs view
@@ -45,9 +45,10 @@ import GHC.Tc.Module ( runTcInteractive )  import GHC.Core.Type-import GHC.Core.TyCon     ( tyConDataCons )+import GHC.Core.TyCo.Compare( eqType )+import GHC.Core.TyCon       ( tyConDataCons ) import GHC.Core-import GHC.Core.FVs       ( exprsSomeFreeVarsList )+import GHC.Core.FVs       ( exprsSomeFreeVarsList, exprFreeVars ) import GHC.Core.SimpleOpt ( simpleOptPgm, simpleOptExpr ) import GHC.Core.Utils import GHC.Core.Unfold.Make@@ -145,7 +146,8 @@    = do { let dflags = hsc_dflags hsc_env              logger = hsc_logger hsc_env-             print_unqual = mkPrintUnqualified (hsc_unit_env hsc_env) rdr_env+             ptc = initPromotionTickContext (hsc_dflags hsc_env)+             name_ppr_ctx = mkNamePprCtx ptc (hsc_unit_env hsc_env) rdr_env         ; withTiming logger                      (text "Desugar"<+>brackets (ppr mod))                      (const ()) $@@ -211,7 +213,7 @@         -- You might think it doesn't matter, but the simplifier brings all top-level         -- things into the in-scope set before simplifying; so we get no unfolding for F#! -        ; endPassHscEnvIO hsc_env print_unqual CoreDesugar final_pgm rules_for_imps+        ; endPassHscEnvIO hsc_env name_ppr_ctx CoreDesugar final_pgm rules_for_imps         ; let simpl_opts = initSimpleOpts dflags         ; let (ds_binds, ds_rules_for_imps, occ_anald_binds)                 = simpleOptPgm simpl_opts mod final_pgm rules_for_imps@@ -220,7 +222,7 @@         ; putDumpFileMaybe logger Opt_D_dump_occur_anal "Occurrence analysis"             FormatCore (pprCoreBindings occ_anald_binds $$ pprRules ds_rules_for_imps ) -        ; endPassHscEnvIO hsc_env print_unqual CoreDesugarOpt ds_binds ds_rules_for_imps+        ; endPassHscEnvIO hsc_env name_ppr_ctx CoreDesugarOpt ds_binds ds_rules_for_imps          ; let used_names = mkUsedNames tcg_env               pluginModules = map lpModule (loadedPlugins (hsc_plugins hsc_env))@@ -462,7 +464,7 @@         -- Substitute the dict bindings eagerly,         -- and take the body apart into a (f args) form         ; dflags <- getDynFlags-        ; case decomposeRuleLhs dflags bndrs'' lhs'' of {+        ; case decomposeRuleLhs dflags bndrs'' lhs'' (exprFreeVars rhs'') of {                 Left msg -> do { diagnosticDs msg; return Nothing } ;                 Right (final_bndrs, fn_id, args) -> do @@ -746,11 +748,11 @@                           , openAlphaTyVar, openBetaTyVar                           , x ] $                    mkSingleAltCase scrut1-                                   (mkWildValBinder Many scrut1_ty)+                                   (mkWildValBinder ManyTy scrut1_ty)                                    (DataAlt unsafe_refl_data_con)                                    [rr_cv] $                    mkSingleAltCase scrut2-                                   (mkWildValBinder Many scrut2_ty)+                                   (mkWildValBinder ManyTy scrut2_ty)                                    (DataAlt unsafe_refl_data_con)                                    [ab_cv] $                    Var x `mkCast` x_co
compiler/GHC/HsToCore/Arrows.hs view
@@ -2,8 +2,6 @@ {-# LANGUAGE BlockArguments #-} {-# LANGUAGE TupleSections #-} -{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}- {- (c) The University of Glasgow 2006 (c) The GRASP/AQUA Project, Glasgow University, 1992-1998@@ -87,7 +85,7 @@   where     mk_bind (std_name, expr)       = do { rhs <- dsExpr expr-           ; id <- newSysLocalDs Many (exprType rhs)+           ; id <- newSysLocalDs ManyTy (exprType rhs)            -- no check needed; these are functions            ; return (NonRec id rhs, (std_name, id)) } @@ -136,18 +134,18 @@ -- construct CoreExpr for \ (a :: a_ty, b :: b_ty) -> a mkFstExpr :: Type -> Type -> DsM CoreExpr mkFstExpr a_ty b_ty = do-    a_var <- newSysLocalDs Many a_ty-    b_var <- newSysLocalDs Many b_ty-    pair_var <- newSysLocalDs Many (mkCorePairTy a_ty b_ty)+    a_var <- newSysLocalDs ManyTy a_ty+    b_var <- newSysLocalDs ManyTy b_ty+    pair_var <- newSysLocalDs ManyTy (mkCorePairTy a_ty b_ty)     return (Lam pair_var                (coreCasePair pair_var a_var b_var (Var a_var)))  -- construct CoreExpr for \ (a :: a_ty, b :: b_ty) -> b mkSndExpr :: Type -> Type -> DsM CoreExpr mkSndExpr a_ty b_ty = do-    a_var <- newSysLocalDs Many a_ty-    b_var <- newSysLocalDs Many b_ty-    pair_var <- newSysLocalDs Many (mkCorePairTy a_ty b_ty)+    a_var <- newSysLocalDs ManyTy a_ty+    b_var <- newSysLocalDs ManyTy b_ty+    pair_var <- newSysLocalDs ManyTy (mkCorePairTy a_ty b_ty)     return (Lam pair_var                (coreCasePair pair_var a_var b_var (Var b_var))) @@ -162,7 +160,7 @@  coreCaseTuple :: UniqSupply -> Id -> [Id] -> CoreExpr -> CoreExpr coreCaseTuple uniqs scrut_var vars body-  = mkTupleCase uniqs vars body scrut_var (Var scrut_var)+  = mkBigTupleCase uniqs vars body (Var scrut_var)  coreCasePair :: Id -> Id -> Id -> CoreExpr -> CoreExpr coreCasePair scrut_var var1 var2 body@@ -178,11 +176,20 @@ mkCoreUnitExpr :: CoreExpr mkCoreUnitExpr = mkCoreTup [] -{--The input is divided into a local environment, which is a flat tuple-(unless it's too big), and a stack, which is a right-nested pair.-In general, the input has the form+{- Note [Environment and stack]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The input is divided into +* A local environment, which is a flat tuple (unless it's too big)+  The elements of the local environment can be+  - of kind Type (for ordinary variables), or+  - of kind Constraint (for dictionaries bound by patterns)++* A stack, which is a right-nested pair.+  The elements on the stack are always of kind Type.++So in general, the input has the form+         ((x1,...,xn), (s1,...(sk,())...))  where xi are the environment values, and si the ones on the stack,@@ -225,9 +232,9 @@                 -> DsM CoreExpr matchEnvStack env_ids stack_id body = do     uniqs <- newUniqueSupply-    tup_var <- newSysLocalDs Many (mkBigCoreVarTupTy env_ids)+    tup_var <- newSysLocalDs ManyTy (mkBigCoreVarTupTy env_ids)     let match_env = coreCaseTuple uniqs tup_var env_ids body-    pair_id <- newSysLocalDs Many (mkCorePairTy (idType tup_var) (idType stack_id))+    pair_id <- newSysLocalDs ManyTy (mkCorePairTy (idType tup_var) (idType stack_id))     return (Lam pair_id (coreCasePair pair_id tup_var stack_id match_env))  ----------------------------------------------@@ -244,7 +251,7 @@          -> DsM CoreExpr matchEnv env_ids body = do     uniqs <- newUniqueSupply-    tup_id <- newSysLocalDs Many (mkBigCoreVarTupTy env_ids)+    tup_id <- newSysLocalDs ManyTy (mkBigCoreVarTupTy env_ids)     return (Lam tup_id (coreCaseTuple uniqs tup_id env_ids body))  ----------------------------------------------@@ -259,7 +266,7 @@ matchVarStack [] stack_id body = return (stack_id, body) matchVarStack (param_id:param_ids) stack_id body = do     (tail_id, tail_code) <- matchVarStack param_ids stack_id body-    pair_id <- newSysLocalDs Many (mkCorePairTy (idType param_id) (idType tail_id))+    pair_id <- newSysLocalDs ManyTy (mkCorePairTy (idType param_id) (idType tail_id))     return (pair_id, coreCasePair pair_id param_id tail_id tail_code)  mkHsEnvStackExpr :: [Id] -> Id -> LHsExpr GhcTc@@ -288,7 +295,7 @@     let env_stk_ty = mkCorePairTy env_ty unitTy     let env_stk_expr = mkCorePairExpr (mkBigCoreVarTup env_ids) mkCoreUnitExpr     fail_expr <- mkFailExpr (ArrowMatchCtxt ProcExpr) env_stk_ty-    var <- selectSimpleMatchVarL Many pat+    var <- selectSimpleMatchVarL ManyTy pat     match_code <- matchSimply (Var var) (ArrowMatchCtxt ProcExpr) pat env_stk_expr fail_expr     let pat_ty = hsLPatType pat     let proc_code = do_premap meth_ids pat_ty env_stk_ty cmd_ty@@ -337,7 +344,7 @@         (_a_ty, arg_ty) = tcSplitAppTy a_arg_ty     core_arrow <- dsLExpr arrow     core_arg   <- dsLExpr arg-    stack_id   <- newSysLocalDs Many stack_ty+    stack_id   <- newSysLocalDs ManyTy stack_ty     core_make_arg <- matchEnvStack env_ids stack_id core_arg     return (do_premap ids               (envStackType env_ids stack_ty)@@ -363,7 +370,7 @@      core_arrow <- dsLExpr arrow     core_arg   <- dsLExpr arg-    stack_id   <- newSysLocalDs Many stack_ty+    stack_id   <- newSysLocalDs ManyTy stack_ty     core_make_pair <- matchEnvStack env_ids stack_id           (mkCorePairExpr core_arrow core_arg) @@ -390,8 +397,8 @@         stack_ty' = mkCorePairTy arg_ty stack_ty     (core_cmd, free_vars, env_ids')              <- dsfixCmd ids local_vars stack_ty' res_ty cmd-    stack_id <- newSysLocalDs Many stack_ty-    arg_id <- newSysLocalDs Many arg_ty+    stack_id <- newSysLocalDs ManyTy stack_ty+    arg_id <- newSysLocalDs ManyTy arg_ty     -- push the argument expression onto the stack     let         stack' = mkCorePairExpr (Var arg_id) (Var stack_id)@@ -436,7 +443,7 @@        <- dsfixCmd ids local_vars stack_ty res_ty then_cmd     (core_else, fvs_else, else_ids)        <- dsfixCmd ids local_vars stack_ty res_ty else_cmd-    stack_id   <- newSysLocalDs Many stack_ty+    stack_id   <- newSysLocalDs ManyTy stack_ty     either_con <- dsLookupTyCon eitherTyConName     left_con   <- dsLookupDataCon leftDataConName     right_con  <- dsLookupDataCon rightDataConName@@ -498,7 +505,7 @@ -}  dsCmd ids local_vars stack_ty res_ty (HsCmdCase _ exp match) env_ids = do-    stack_id <- newSysLocalDs Many stack_ty+    stack_id <- newSysLocalDs ManyTy stack_ty     (match', core_choices)       <- dsCases ids local_vars stack_id stack_ty res_ty match     let MG{ mg_ext = MatchGroupTc _ sum_ty _ } = match'@@ -540,7 +547,7 @@      -- construct and desugar a case expression with multiple scrutinees     (core_body, free_vars, env_ids') <- trimInput \env_ids -> do-      stack_id <- newSysLocalDs Many stack_ty'+      stack_id <- newSysLocalDs ManyTy stack_ty'       (match', core_choices)         <- dsCases ids local_vars' stack_id stack_ty' res_ty match @@ -556,8 +563,8 @@       return (do_premap ids in_ty sum_ty res_ty core_matches core_choices,               exprFreeIdsDSet core_body `uniqDSetIntersectUniqSet` local_vars') -    param_ids <- mapM (newSysLocalDs Many) pat_tys-    stack_id' <- newSysLocalDs Many stack_ty'+    param_ids <- mapM (newSysLocalDs ManyTy) pat_tys+    stack_id' <- newSysLocalDs ManyTy stack_ty'      -- the expression is built from the inside out, so the actions     -- are presented in reverse order@@ -592,7 +599,7 @@      (core_body, _free_vars, env_ids')        <- dsfixCmd ids local_vars' stack_ty res_ty body-    stack_id <- newSysLocalDs Many stack_ty+    stack_id <- newSysLocalDs ManyTy stack_ty     -- build a new environment, plus the stack, using the let bindings     core_binds <- dsLocalBinds lbinds (buildEnvStack env_ids' stack_id)     -- match the old environment and stack against the input@@ -658,7 +665,7 @@     (meth_binds, meth_ids) <- mkCmdEnv ids     (core_cmd, free_vars, env_ids')        <- dsfixCmd meth_ids local_vars stack_ty cmd_ty cmd-    stack_id <- newSysLocalDs Many stack_ty+    stack_id <- newSysLocalDs ManyTy stack_ty     trim_code       <- matchEnvStack env_ids stack_id (buildEnvStack env_ids' stack_id)     let@@ -722,8 +729,8 @@         (pat_tys, stack_ty') = splitTypeAt (length pats) stack_ty     (core_body, free_vars, env_ids')        <- dsfixCmd ids local_vars' stack_ty' res_ty body-    param_ids <- mapM (newSysLocalDs Many) pat_tys-    stack_id' <- newSysLocalDs Many stack_ty'+    param_ids <- mapM (newSysLocalDs ManyTy) pat_tys+    stack_id' <- newSysLocalDs ManyTy stack_ty'      -- the expression is built from the inside out, so the actions     -- are presented in reverse order@@ -805,7 +812,7 @@     Nothing -> ([], void_ty,) . do_arr ids void_ty res_ty <$>       dsExpr (HsLamCase EpAnnNotUsed LamCase         (MG { mg_alts = noLocA []-            , mg_ext = MatchGroupTc [Scaled Many void_ty] res_ty Generated+            , mg_ext = MatchGroupTc [Scaled ManyTy void_ty] res_ty Generated             }))        -- Replace the commands in the case with these tagged tuples,@@ -847,7 +854,7 @@ dsCmdDo ids local_vars res_ty [L _ (LastStmt _ body _ _)] env_ids = do     (core_body, env_ids') <- dsLCmd ids local_vars unitTy res_ty body env_ids     let env_ty = mkBigCoreVarTupTy env_ids-    env_var <- newSysLocalDs Many env_ty+    env_var <- newSysLocalDs ManyTy env_ty     let core_map = Lam env_var (mkCorePairExpr (Var env_var) mkCoreUnitExpr)     return (do_premap ids                         env_ty@@ -949,7 +956,7 @@     -- projection function     --          \ (p, (xs2)) -> (zs) -    env_id <- newSysLocalDs Many env_ty2+    env_id <- newSysLocalDs ManyTy env_ty2     uniqs <- newUniqueSupply     let        after_c_ty = mkCorePairTy pat_ty env_ty2@@ -957,10 +964,10 @@        body_expr = coreCaseTuple uniqs env_id env_ids2 (mkBigCoreVarTup out_ids)      fail_expr <- mkFailExpr (StmtCtxt (HsDoStmt (DoExpr Nothing))) out_ty-    pat_id    <- selectSimpleMatchVarL Many pat+    pat_id    <- selectSimpleMatchVarL ManyTy pat     match_code       <- matchSimply (Var pat_id) (StmtCtxt (HsDoStmt (DoExpr Nothing))) pat body_expr fail_expr-    pair_id   <- newSysLocalDs Many after_c_ty+    pair_id   <- newSysLocalDs ManyTy after_c_ty     let         proj_expr = Lam pair_id (coreCasePair pair_id pat_id env_id match_code) @@ -1023,7 +1030,7 @@     -- post_loop_fn = \((later_ids),(env2_ids)) -> (out_ids)      uniqs <- newUniqueSupply-    env2_id <- newSysLocalDs Many env2_ty+    env2_id <- newSysLocalDs ManyTy env2_ty     let         later_ty = mkBigCoreVarTupTy later_ids         post_pair_ty = mkCorePairTy later_ty env2_ty@@ -1110,7 +1117,7 @@      -- squash_pair_fn = \ ((env1_ids), ~(rec_ids)) -> (env_ids) -    rec_id <- newSysLocalDs Many rec_ty+    rec_id <- newSysLocalDs ManyTy rec_ty     let         env1_id_set = fv_stmts `uniqDSetMinusUniqSet` rec_id_set         env1_ids = dVarSetElems env1_id_set@@ -1120,7 +1127,7 @@           where             selectVar v                 | v `elemVarSet` rec_id_set-                  = mkTupleSelector rec_ids v rec_id (Var rec_id)+                  = mkBigTupleSelector rec_ids v rec_id (Var rec_id)                 | otherwise = Var v      squash_pair_fn <- matchEnvStack env1_ids rec_id core_body
compiler/GHC/HsToCore/Binds.hs view
@@ -2,8 +2,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-} -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}- {- (c) The University of Glasgow 2006 (c) The GRASP/AQUA Project, Glasgow University, 1992-1998@@ -54,6 +52,7 @@ import GHC.Core.Coercion import GHC.Core.Multiplicity import GHC.Core.Rules+import GHC.Core.TyCo.Compare( eqType )  import GHC.Builtin.Names import GHC.Builtin.Types ( naturalTy, typeSymbolKind, charTy )@@ -80,7 +79,6 @@ import GHC.Utils.Outputable import GHC.Utils.Panic import GHC.Utils.Panic.Plain-import GHC.Utils.Trace  import Control.Monad @@ -299,7 +297,7 @@                             mkLet aux_binds $                             tup_expr -       ; poly_tup_id <- newSysLocalDs Many (exprType poly_tup_rhs)+       ; poly_tup_id <- newSysLocalDs ManyTy (exprType poly_tup_rhs)          -- Find corresponding global or make up a new one: sometimes         -- we need to make new export to desugar strict binds, see@@ -310,10 +308,10 @@                           , abe_poly = global                           , abe_mono = local, abe_prags = spec_prags })                           -- See Note [AbsBinds wrappers] in "GHC.Hs.Binds"-                = do { tup_id  <- newSysLocalDs Many tup_ty+                = do { tup_id  <- newSysLocalDs ManyTy tup_ty                      ; core_wrap <- dsHsWrapper wrap                      ; let rhs = core_wrap $ mkLams tyvars $ mkLams dicts $-                                 mkTupleSelector all_locals local tup_id $+                                 mkBigTupleSelector all_locals local tup_id $                                  mkVarApps (Var poly_tup_id) (tyvars ++ dicts)                            rhs_for_spec = Let (NonRec poly_tup_id poly_tup_rhs) rhs                      ; (spec_binds, rules) <- dsSpecs rhs_for_spec spec_prags@@ -370,7 +368,7 @@             ([],[]) lcls      mk_export local =-      do global <- newSysLocalDs Many+      do global <- newSysLocalDs ManyTy                      (exprType (mkLams tyvars (mkLams dicts (Var local))))          return (ABE { abe_poly  = global                      , abe_mono  = local@@ -708,7 +706,7 @@          --                         , text "spec_co:" <+> ppr spec_co          --                         , text "ds_rhs:" <+> ppr ds_lhs ]) $          dflags <- getDynFlags-       ; case decomposeRuleLhs dflags spec_bndrs ds_lhs of {+       ; case decomposeRuleLhs dflags spec_bndrs ds_lhs (mkVarSet spec_bndrs) of {            Left msg -> do { diagnosticDs msg; return Nothing } ;            Right (rule_bndrs, _fn, rule_lhs_args) -> do @@ -716,7 +714,7 @@        ; let fn_unf    = realIdUnfolding poly_id              simpl_opts = initSimpleOpts dflags              spec_unf   = specUnfolding simpl_opts spec_bndrs core_app rule_lhs_args fn_unf-             spec_id    = mkLocalId spec_name Many spec_ty -- Specialised binding is toplevel, hence Many.+             spec_id    = mkLocalId spec_name ManyTy spec_ty -- Specialised binding is toplevel, hence Many.                             `setInlinePragma` inl_prag                             `setIdUnfolding`  spec_unf @@ -835,6 +833,7 @@ -}  decomposeRuleLhs :: DynFlags -> [Var] -> CoreExpr+                 -> VarSet   -- Free vars of the RHS                  -> Either DsMessage ([Var], Id, [CoreExpr]) -- (decomposeRuleLhs bndrs lhs) takes apart the LHS of a RULE, -- The 'bndrs' are the quantified binders of the rules, but decomposeRuleLhs@@ -842,49 +841,65 @@ -- -- Returns an error message if the LHS isn't of the expected shape -- Note [Decomposing the left-hand side of a RULE]-decomposeRuleLhs dflags orig_bndrs orig_lhs-  | not (null unbound)    -- Check for things unbound on LHS-                          -- See Note [Unused spec binders]-  = Left (DsRuleBindersNotBound unbound orig_bndrs orig_lhs lhs2)+decomposeRuleLhs dflags orig_bndrs orig_lhs rhs_fvs   | Var funId <- fun2   , Just con <- isDataConId_maybe funId   = Left (DsRuleIgnoredDueToConstructor con) -- See Note [No RULES on datacons]-  | Just (fn_id, args) <- decompose fun2 args2-  , let extra_bndrs = mk_extra_bndrs fn_id args-  = -- pprTrace "decomposeRuleLhs" (vcat [ text "orig_bndrs:" <+> ppr orig_bndrs-    --                                  , text "orig_lhs:" <+> ppr orig_lhs-    --                                  , text "lhs1:"     <+> ppr lhs1-    --                                  , text "extra_bndrs:" <+> ppr extra_bndrs-    --                                  , text "fn_id:" <+> ppr fn_id-    --                                  , text "args:"   <+> ppr args]) $-    Right (orig_bndrs ++ extra_bndrs, fn_id, args) -  | otherwise-  = Left (DsRuleLhsTooComplicated orig_lhs lhs2)- where-   simpl_opts   = initSimpleOpts dflags-   lhs1         = drop_dicts orig_lhs-   lhs2         = simpleOptExpr simpl_opts lhs1  -- See Note [Simplify rule LHS]-   (fun2,args2) = collectArgs lhs2+  | otherwise = case decompose fun2 args2 of+        Nothing -> Left (DsRuleLhsTooComplicated orig_lhs lhs2)+        Just (fn_id, args)+          | not (null unbound) ->+            -- Check for things unbound on LHS+            -- See Note [Unused spec binders]+            -- pprTrace "decomposeRuleLhs 1" (vcat [ text "orig_bndrs:" <+> ppr orig_bndrs+            --                                     , text "orig_lhs:" <+> ppr orig_lhs+            --                                     , text "lhs_fvs:" <+> ppr lhs_fvs+            --                                     , text "rhs_fvs:" <+> ppr rhs_fvs+            --                                     , text "unbound:" <+> ppr unbound+            --                                     ]) $+            Left (DsRuleBindersNotBound unbound orig_bndrs orig_lhs lhs2)+          | otherwise ->+            -- pprTrace "decomposeRuleLhs 2" (vcat [ text "orig_bndrs:" <+> ppr orig_bndrs+            --                                    , text "orig_lhs:" <+> ppr orig_lhs+            --                                    , text "lhs1:"     <+> ppr lhs1+            --                                    , text "extra_bndrs:" <+> ppr extra_bndrs+            --                                    , text "fn_id:" <+> ppr fn_id+            --                                    , text "args:"   <+> ppr args+            --                                    , text "args fvs:" <+> ppr (exprsFreeVarsList args)+            --                                    ]) $+            Right (trimmed_bndrs ++ extra_bndrs, fn_id, args) -   lhs_fvs    = exprFreeVars lhs2-   unbound    = filterOut (`elemVarSet` lhs_fvs) orig_bndrs+          where -- See Note [Variables unbound on the LHS]+                lhs_fvs = exprsFreeVars args+                all_fvs       = lhs_fvs `unionVarSet` rhs_fvs+                trimmed_bndrs = filter (`elemVarSet` all_fvs) orig_bndrs+                unbound       = filterOut (`elemVarSet` lhs_fvs) trimmed_bndrs+                    -- Needed on RHS but not bound on LHS +                -- Add extra tyvar binders: Note [Free tyvars on rule LHS]+                -- and extra dict binders: Note [Free dictionaries on rule LHS]+                extra_bndrs = scopedSort extra_tvs ++ extra_dicts+                  where+                    extra_tvs   = [ v | v <- extra_vars, isTyVar v ]+                extra_dicts =+                  [ mkLocalId (localiseName (idName d)) ManyTy (idType d)+                  | d <- extra_vars, isDictId d ]+                extra_vars  =+                  [ v+                  | v <- exprsFreeVarsList args+                  , not (v `elemVarSet` orig_bndr_set)+                  , not (v == fn_id) ]+                    -- fn_id: do not quantify over the function itself, which may+                    -- itself be a dictionary (in pathological cases, #10251)++ where+   simpl_opts    = initSimpleOpts dflags    orig_bndr_set = mkVarSet orig_bndrs -        -- Add extra tyvar binders: Note [Free tyvars on rule LHS]-        -- and extra dict binders: Note [Free dictionaries on rule LHS]-   mk_extra_bndrs fn_id args-     = scopedSort unbound_tvs ++ unbound_dicts-     where-       unbound_tvs   = [ v | v <- unbound_vars, isTyVar v ]-       unbound_dicts = [ mkLocalId (localiseName (idName d)) Many (idType d)-                       | d <- unbound_vars, isDictId d ]-       unbound_vars  = [ v | v <- exprsFreeVarsList args-                           , not (v `elemVarSet` orig_bndr_set)-                           , not (v == fn_id) ]-         -- fn_id: do not quantify over the function itself, which may-         -- itself be a dictionary (in pathological cases, #10251)+   lhs1         = drop_dicts orig_lhs+   lhs2         = simpleOptExpr simpl_opts lhs1  -- See Note [Simplify rule LHS]+   (fun2,args2) = collectArgs lhs2     decompose (Var fn_id) args       | not (fn_id `elemVarSet` orig_bndr_set)@@ -926,6 +941,27 @@        needed' = (needed `minusVarSet` rhs_fvs) `extendVarSet` d  {-+Note [Variables unbound on the LHS]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We obviously want to complain about+   RULE   forall x. f True = not x+because the forall'd variable `x` is not bound on the LHS.++It can be a bit delicate when dictionaries are involved.+Consider #22471+  {-# RULES "foo" forall (f :: forall a. [a] -> Int).+                  foo (\xs. 1 + f xs) = 2 + foo f #-}++We get two dicts on the LHS, one from `1` and one from `+`.+For reasons described in Note [The SimplifyRule Plan] in+GHC.Tc.Gen.Rule, we quantify separately over those dictionaries:+   forall f (d1::Num Int) (d2 :: Num Int).+   foo (\xs. (+) d1 (fromInteger d2 1) xs) = ...++Now the desugarer shortcircuits (fromInteger d2 1) to (I# 1); so d2 is+not mentioned at all (on LHS or RHS)! We don't want to complain about+and unbound d2.  Hence the trimmed_bndrs.+ Note [Decomposing the left-hand side of a RULE] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are several things going on here.@@ -956,6 +992,9 @@ see Note [Free dictionaries on rule LHS].   So that's why we look for type variables free on the LHS, and quantify over them. +This relies on there not being any in-scope tyvars, which is true for+user-defined RULEs, which are always top-level.+ Note [Free dictionaries on rule LHS] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When the LHS of a specialisation rule, (/\as\ds. f es) has a free dict,@@ -1212,8 +1251,7 @@ dsEvTypeable ty ev   = do { tyCl <- dsLookupTyCon typeableClassName    -- Typeable        ; let kind = typeKind ty-             Just typeable_data_con-                 = tyConSingleDataCon_maybe tyCl    -- "Data constructor"+             typeable_data_con = tyConSingleDataCon tyCl  -- "Data constructor"                                                     -- for Typeable         ; rep_expr <- ds_ev_typeable ty ev           -- :: TypeRep a@@ -1270,7 +1308,7 @@        }  ds_ev_typeable ty (EvTypeableTrFun evm ev1 ev2)-  | Just (m,t1,t2) <- splitFunTy_maybe ty+  | Just (_af,m,t1,t2) <- splitFunTy_maybe ty   = do { e1 <- getRep ev1 t1        ; e2 <- getRep ev2 t2        ; em <- getRep evm m
compiler/GHC/HsToCore/Coverage.hs view
@@ -116,7 +116,7 @@ hpcInitCode platform this_mod (HpcInfo tickCount hashNo)  = initializerCStub platform fn_name decls body   where-    fn_name = mkInitializerStubLabel this_mod "hpc"+    fn_name = mkInitializerStubLabel this_mod (fsLit "hpc")     decls = text "extern StgWord64 " <> tickboxes <> text "[]" <> semi     body = text "hs_hpc_module" <>               parens (hcat (punctuate comma [
compiler/GHC/HsToCore/Expr.hs view
@@ -3,7 +3,6 @@ {-# LANGUAGE ViewPatterns #-}  {-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}-{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}  {- (c) The University of Glasgow 2006@@ -208,7 +207,7 @@              eqn = EqnInfo { eqn_pats = [upat],                              eqn_orig = FromSource,                              eqn_rhs = cantFailMatchResult body }-       ; var    <- selectMatchVar Many upat+       ; var    <- selectMatchVar ManyTy upat                     -- `var` will end up in a let binder, so the multiplicity                     -- doesn't matter.        ; result <- matchEquations PatBindRhs [var] [eqn] (exprType body)@@ -369,7 +368,7 @@                         -- See Note [Don't flatten tuples from HsSyn] in GHC.Core.Make  dsExpr (ExplicitSum types alt arity expr)-  = mkCoreUbxSum arity alt types <$> dsLExpr expr+  = mkCoreUnboxedSum arity alt types <$> dsLExpr expr  dsExpr (HsPragE _ prag expr) =   ds_prag_expr prag expr@@ -715,7 +714,7 @@            ; body' <- dsLExpr $ noLocA $ HsDo body_ty ctx (noLocA stmts)             ; let match_args (pat, fail_op) (vs,body)-                   = do { var   <- selectSimpleMatchVarL Many pat+                   = do { var   <- selectSimpleMatchVarL ManyTy pat                         ; match <- matchSinglePatVar var Nothing (StmtCtxt (HsDoStmt ctx)) pat                                    body_ty (cantFailMatchResult body)                         ; match_code <- dsHandleMonadicFailure ctx pat match fail_op@@ -741,10 +740,10 @@       where         new_bind_stmt = L loc $ BindStmt           XBindStmtTc-            { xbstc_bindOp = bind_op+            { xbstc_bindOp          = bind_op             , xbstc_boundResultType = bind_ty-            , xbstc_boundResultMult = Many-            , xbstc_failOp = Nothing -- Tuple cannot fail+            , xbstc_boundResultMult = ManyTy+            , xbstc_failOp          = Nothing -- Tuple cannot fail             }           (mkBigLHsPatTupId later_pats)           mfix_app
compiler/GHC/HsToCore/Foreign/C.hs view
@@ -81,7 +81,7 @@     let        ty                     = coercionRKind co        (bndrs, orig_res_ty)   = tcSplitPiTys ty-       fe_arg_tys'            = mapMaybe binderRelevantType_maybe bndrs+       fe_arg_tys'            = mapMaybe anonPiTyBinderType_maybe bndrs        -- We must use tcSplits here, because we want to see        -- the (IO t) in the corner of the type!        fe_arg_tys | isDyn     = tail fe_arg_tys'@@ -189,7 +189,7 @@         stable_ptr_ty = mkTyConApp stable_ptr_tycon [arg_ty]         export_ty     = mkVisFunTyMany stable_ptr_ty arg_ty     bindIOId <- dsLookupGlobalId bindIOName-    stbl_value <- newSysLocalDs Many stable_ptr_ty+    stbl_value <- newSysLocalDs ManyTy stable_ptr_ty     (h_code, c_code, typestring, args_size) <- dsCFExport id (mkRepReflCo export_ty) fe_nm cconv True     let          {-@@ -246,10 +246,18 @@         -> DsM ([(Id, Expr TyVar)], CHeader, CStub) dsFCall fn_id co fcall mDeclHeader = do     let-        ty                   = coercionLKind co+        (ty,ty1)             = (coercionLKind co, coercionRKind co)         (tv_bndrs, rho)      = tcSplitForAllTyVarBinders ty         (arg_tys, io_res_ty) = tcSplitFunTys rho +    let constQual -- provide 'const' qualifier (#22034)+          | (_, res_ty1) <- tcSplitFunTys ty1+          , newty <- maybe res_ty1 snd (tcSplitIOType_maybe res_ty1)+          , Just (ptr, _) <- splitTyConApp_maybe newty+          , tyConName ptr `elem` [constPtrConName]+          = text "const"+          | otherwise = empty+     args <- newSysLocalsDs arg_tys  -- no FFI representation polymorphism     (val_args, arg_wrappers) <- mapAndUnzipM unboxArg (map Var args) @@ -277,7 +285,7 @@                       includes = vcat [ text "#include \"" <> ftext h                                         <> text "\""                                       | Header _ h <- nub headers ]-                      fun_proto = cResType <+> pprCconv <+> ppr wrapperName <> parens argTypes+                      fun_proto = constQual <+> cResType <+> pprCconv <+> ppr wrapperName <> parens argTypes                       cRet                        | isVoidRes =                   cCall                        | otherwise = text "return" <+> cCall@@ -316,7 +324,7 @@         tvs           = map binderVar tv_bndrs         the_ccall_app = mkFCall ccall_uniq fcall' val_args ccall_result_ty         work_rhs      = mkLams tvs (mkLams work_arg_ids the_ccall_app)-        work_id       = mkSysLocal (fsLit "$wccall") work_uniq Many worker_ty+        work_id       = mkSysLocal (fsLit "$wccall") work_uniq ManyTy worker_ty          -- Build the wrapper         work_app     = mkApps (mkVarApps (Var work_id) tvs) val_args@@ -618,7 +626,7 @@     tyConUnique tc == funPtrTyConKey   = let        (bndrs, _) = tcSplitPiTys arg_ty-       fe_arg_tys = mapMaybe binderRelevantType_maybe bndrs+       fe_arg_tys = mapMaybe anonPiTyBinderType_maybe bndrs     in Just $ sum (map (widthInBytes . typeWidth . typeCmmType platform . getPrimTyOf) fe_arg_tys) fun_type_arg_stdcall_info _ _other_conv _   = Nothing
compiler/GHC/HsToCore/Foreign/Call.hs view
@@ -150,7 +150,7 @@     tc `hasKey` boolTyConKey   = do dflags <- getDynFlags        let platform = targetPlatform dflags-       prim_arg <- newSysLocalDs Many intPrimTy+       prim_arg <- newSysLocalDs ManyTy intPrimTy        return (Var prim_arg,               \ body -> Case (mkIfThenElse arg (mkIntLit platform 1) (mkIntLit platform 0))                              prim_arg@@ -162,8 +162,8 @@   | is_product_type && data_con_arity == 1   = assertPpr (isUnliftedType data_con_arg_ty1) (pprType arg_ty) $                         -- Typechecker ensures this-    do case_bndr <- newSysLocalDs Many arg_ty-       prim_arg <- newSysLocalDs Many data_con_arg_ty1+    do case_bndr <- newSysLocalDs ManyTy arg_ty+       prim_arg <- newSysLocalDs ManyTy data_con_arg_ty1        return (Var prim_arg,                \ body -> Case arg case_bndr (exprType body) [Alt (DataAlt data_con) [prim_arg] body]               )@@ -177,7 +177,7 @@     isJust maybe_arg3_tycon &&     (arg3_tycon ==  byteArrayPrimTyCon ||      arg3_tycon ==  mutableByteArrayPrimTyCon)-  = do case_bndr <- newSysLocalDs Many arg_ty+  = do case_bndr <- newSysLocalDs ManyTy arg_ty        vars@[_l_var, _r_var, arr_cts_var] <- newSysLocalsDs (map unrestricted data_con_arg_tys)        return (Var arr_cts_var,                \ body -> Case arg case_bndr (exprType body) [Alt (DataAlt data_con) vars body]@@ -223,14 +223,11 @@         -- another case, and a coercion.)         -- The result is IO t, so wrap the result in an IO constructor   = do  { res <- resultWrapper io_res_ty-        ; let return_result state anss-                = mkCoreUbxTup-                    [realWorldStatePrimTy, io_res_ty]-                    [state, anss]+        ; let return_result state anss = mkCoreUnboxedTuple [state, anss]          ; (ccall_res_ty, the_alt) <- mk_alt return_result res -        ; state_id <- newSysLocalDs Many realWorldStatePrimTy+        ; state_id <- newSysLocalDs ManyTy realWorldStatePrimTy         ; let io_data_con = head (tyConDataCons io_tycon)               toIOCon     = dataConWrapId io_data_con @@ -266,7 +263,7 @@        -> DsM (Type, CoreAlt) mk_alt return_result (Nothing, wrap_result)   = do -- The ccall returns ()-       state_id <- newSysLocalDs Many realWorldStatePrimTy+       state_id <- newSysLocalDs ManyTy realWorldStatePrimTy        let              the_rhs = return_result (Var state_id)                                      (wrap_result (panic "boxResult"))@@ -280,8 +277,8 @@   = -- The ccall returns a non-() value     assertPpr (isPrimitiveType prim_res_ty) (ppr prim_res_ty) $              -- True because resultWrapper ensures it is so-    do { result_id <- newSysLocalDs Many prim_res_ty-       ; state_id <- newSysLocalDs Many realWorldStatePrimTy+    do { result_id <- newSysLocalDs ManyTy prim_res_ty+       ; state_id <- newSysLocalDs ManyTy realWorldStatePrimTy        ; let the_rhs = return_result (Var state_id)                                 (wrap_result (Var result_id))              ccall_res_ty = mkTupleTy Unboxed [realWorldStatePrimTy, prim_res_ty]
compiler/GHC/HsToCore/Foreign/Decl.hs view
@@ -2,8 +2,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-} -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}- {- (c) The University of Glasgow 2006 (c) The AQUA Project, Glasgow University, 1998@@ -16,10 +14,12 @@ where  import GHC.Prelude+import GHC.Data.FastString  import GHC.Tc.Utils.Monad        -- temp  import GHC.HsToCore.Foreign.C+import GHC.HsToCore.Foreign.JavaScript import GHC.HsToCore.Foreign.Utils import GHC.HsToCore.Monad @@ -36,7 +36,6 @@ import GHC.Driver.Session import GHC.Platform import GHC.Data.OrdList-import GHC.Utils.Panic import GHC.Driver.Hooks  import Data.List (unzip4)@@ -128,8 +127,11 @@           -> Coercion           -> ForeignImport (GhcPass p)           -> DsM ([Binding], CHeader, CStub)-dsFImport id co (CImport _ cconv safety mHeader spec) =-    dsCImport id co spec (unLoc cconv) (unLoc safety) mHeader+dsFImport id co (CImport _ cconv safety mHeader spec) = do+  platform <- getPlatform+  case platformArch platform of+    ArchJavaScript -> dsJsImport id co spec (unLoc cconv) (unLoc safety) mHeader+    _              -> dsCImport  id co spec (unLoc cconv) (unLoc safety) mHeader  {- ************************************************************************@@ -164,9 +166,11 @@                  , String       -- string describing type to pass to createAdj.                  , Int          -- size of args to stub function                  )-dsFExport fn_id co ext_name cconv is_dyn = case cconv of-  JavaScriptCallConv -> panic "dsFExport: JavaScript foreign exports not supported yet"-  _                  -> dsCFExport  fn_id co ext_name cconv is_dyn+dsFExport fn_id co ext_name cconv is_dyn = do+  platform <- getPlatform+  case platformArch platform of+    ArchJavaScript -> dsJsFExport fn_id co ext_name cconv is_dyn+    _              -> dsCFExport  fn_id co ext_name cconv is_dyn   foreignExportsInitialiser :: Platform -> Module -> [Id] -> CStub@@ -184,7 +188,7 @@    -- See Note [Tracking foreign exports] in rts/ForeignExports.c    initializerCStub platform fn_nm list_decl fn_body   where-    fn_nm       = mkInitializerStubLabel mod "fexports"+    fn_nm       = mkInitializerStubLabel mod (fsLit "fexports")     mod_str     = pprModuleName (moduleName mod)     fn_body     = text "registerForeignExports" <> parens (char '&' <> list_symbol) <> semi     list_symbol = text "stg_exports_" <> mod_str
+ compiler/GHC/HsToCore/Foreign/JavaScript.hs view
@@ -0,0 +1,683 @@+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}++-- | Handling of JavaScript foreign imports/exports+module GHC.HsToCore.Foreign.JavaScript+  ( dsJsImport+  , dsJsFExport+  , dsJsFExportDynamic+  )+where++import GHC.Prelude++import GHC.Platform++import GHC.Hs++import GHC.HsToCore.Monad+import GHC.HsToCore.Foreign.Call+import GHC.HsToCore.Foreign.Prim+import GHC.HsToCore.Foreign.Utils+import GHC.HsToCore.Utils++import GHC.Core+import GHC.Core.Make+import GHC.Core.Utils+import GHC.Core.DataCon+import GHC.Core.Unfold.Make+import GHC.Core.Type+import GHC.Core.TyCon+import GHC.Core.Coercion+import GHC.Core.Multiplicity++import GHC.Types.Id+import GHC.Types.Id.Make+import GHC.Types.Literal+import GHC.Types.ForeignStubs+import GHC.Types.SourceText+import GHC.Types.Name+import GHC.Types.RepType+import GHC.Types.ForeignCall+import GHC.Types.Basic+import GHC.Types.Unique++import GHC.Unit.Module++import GHC.Tc.Utils.TcType++import GHC.Cmm.Expr+import GHC.Cmm.Utils++import GHC.JS.Ppr++import GHC.Driver.Session+import GHC.Driver.Config++import GHC.Builtin.Types+import GHC.Builtin.Types.Prim+import GHC.Builtin.Names++import GHC.Data.FastString+import GHC.Data.Pair+import GHC.Data.Maybe++import GHC.Utils.Outputable+import GHC.Utils.Panic+import GHC.Utils.Encoding++dsJsFExport+  :: Id                 -- Either the exported Id,+                        -- or the foreign-export-dynamic constructor+  -> Coercion           -- Coercion between the Haskell type callable+                        -- from C, and its representation type+  -> CLabelString       -- The name to export to C land+  -> CCallConv+  -> Bool               -- True => foreign export dynamic+                        --         so invoke IO action that's hanging off+                        --         the first argument's stable pointer+  -> DsM ( CHeader      -- contents of Module_stub.h+         , CStub        -- contents of Module_stub.c+         , String       -- string describing type to pass to createAdj.+         , Int          -- size of args to stub function+         )++dsJsFExport fn_id co ext_name cconv isDyn = do+    let+       ty                              = pSnd $ coercionKind co+       (_tvs,sans_foralls)             = tcSplitForAllTyVars ty+       (fe_arg_tys', orig_res_ty)      = tcSplitFunTys sans_foralls+       -- We must use tcSplits here, because we want to see+       -- the (IO t) in the corner of the type!+       fe_arg_tys | isDyn     = tail fe_arg_tys'+                  | otherwise = fe_arg_tys'++       -- Look at the result type of the exported function, orig_res_ty+       -- If it's IO t, return         (t, True)+       -- If it's plain t, return      (t, False)+       (res_ty, is_IO_res_ty) = case tcSplitIOType_maybe orig_res_ty of+                                -- The function already returns IO t+                                Just (_ioTyCon, res_ty) -> (res_ty, True)+                                -- The function returns t+                                Nothing                 -> (orig_res_ty, False)+    platform <- targetPlatform <$> getDynFlags+    return $+      mkFExportJSBits platform ext_name+                     (if isDyn then Nothing else Just fn_id)+                     (map scaledThing fe_arg_tys) res_ty is_IO_res_ty cconv++mkFExportJSBits+  :: Platform+  -> FastString+  -> Maybe Id      -- Just==static, Nothing==dynamic+  -> [Type]+  -> Type+  -> Bool          -- True <=> returns an IO type+  -> CCallConv+  -> (CHeader,+      CStub,+      String,      -- the argument reps+      Int          -- total size of arguments+     )+mkFExportJSBits platform c_nm maybe_target arg_htys res_hty is_IO_res_ty _cconv+ = (header_bits, js_bits, type_string,+    sum [ widthInBytes (typeWidth rep) | (_,_,_,rep) <- arg_info] -- all the args+         -- NB. the calculation here isn't strictly speaking correct.+         -- We have a primitive Haskell type (eg. Int#, Double#), and+         -- we want to know the size, when passed on the C stack, of+         -- the associated C type (eg. HsInt, HsDouble).  We don't have+         -- this information to hand, but we know what GHC's conventions+         -- are for passing around the primitive Haskell types, so we+         -- use that instead.  I hope the two coincide --SDM+    )+ where+  -- list the arguments to the JS function+  arg_info :: [(SDoc,           -- arg name+                SDoc,           -- C type+                Type,           -- Haskell type+                CmmType)]       -- the CmmType+  arg_info  = [ let stg_type = showStgType ty in+                (arg_cname n stg_type,+                 stg_type,+                 ty,+                 typeCmmType platform (getPrimTyOf ty))+              | (ty,n) <- zip arg_htys [1::Int ..] ]++  arg_cname n _stg_ty = text ('a':show n)++  type_string = primTyDescChar platform res_hty : arg_type_string++  arg_type_string = [primTyDescChar platform ty | (_,_,ty,_) <- arg_info]++  -- stuff to do with the return type of the JS function+  res_hty_is_unit = res_hty `eqType` unitTy     -- Look through any newtypes++  unboxResType | res_hty_is_unit = text "h$rts_getUnit"+               | otherwise       = unpackHObj res_hty++  header_bits = maybe mempty idTag maybe_target+  idTag i = let (tag, u) = unpkUnique (getUnique i)+            in  CHeader (char tag <> int u)++  fun_args+    | null arg_info = empty -- text "void"+    | otherwise         = hsep $ punctuate comma+                               $ map (\(nm,_ty,_,_) -> nm) arg_info++  fun_proto+      = text "async" <+>+        text "function" <+>+        (if isNothing maybe_target+         then text "h$" <> ftext c_nm+         else ftext c_nm) <>+        parens fun_args++  fun_export+     = case maybe_target of+          Just hs_fn | Just m <- nameModule_maybe (getName hs_fn) ->+            text "h$foreignExport" <>+                        parens (+                          ftext c_nm <> comma <>+                          strlit (unitIdString (moduleUnitId m)) <> comma <>+                          strlit (moduleNameString (moduleName m)) <> comma <>+                          strlit (unpackFS c_nm) <> comma <>+                          strlit type_string+                        ) <> semi+          _ -> empty++  strlit xs = docToSDoc (pprStringLit (mkFastString xs))++  -- the target which will form the root of what we ask rts_evalIO to run+  the_cfun+     = case maybe_target of+          Nothing    -> text "h$deRefStablePtr(the_stableptr)"+          Just hs_fn -> idClosureText hs_fn++  -- the expression we give to rts_eval+  expr_to_run :: SDoc+  expr_to_run+     = foldl appArg the_cfun arg_info+       where+          appArg acc (arg_cname, _, arg_hty, _)+             = text "h$rts_apply"+               <> parens (acc <> comma <> mkHObj arg_hty <> parens arg_cname)++  -- finally, the whole darn thing+  js_bits = CStub { getCStub        = js_sdoc+                  , getInitializers = mempty+                  , getFinalizers   = mempty+                  }+       where js_sdoc = space+               $$ fun_proto+               $$ vcat+                 [ lbrace+                 ,   text "return"+                     <+> text "await"+                     <+> text "h$rts_eval"+                     <> parens ((if is_IO_res_ty+                                 then expr_to_run+                                 else text "h$rts_toIO" <> parens expr_to_run)+                                <> comma <+> unboxResType)+                     <> semi+                 , rbrace+                 ]+               $$ fun_export++idClosureText :: Id -> SDoc+idClosureText i+  | isExportedId i+  , name <- getName i+  , Just m <- nameModule_maybe name+  = let str = renderWithContext defaultSDocContext (pprFullName m (localiseName name))+    in text "h$" <> text (zEncodeString str)+  | otherwise+  = panic "idClosureText: unknown module"++-- | Desugaring of JavaScript foreign imports+dsJsImport+  :: Id+  -> Coercion+  -> CImportSpec+  -> CCallConv+  -> Safety+  -> Maybe Header+  -> DsM ([Binding], CHeader, CStub)+dsJsImport id co (CLabel cid) cconv _ _ = do+   let ty = pFst $ coercionKind co+       fod = case tyConAppTyCon_maybe (dropForAlls ty) of+             Just tycon+              | tyConUnique tycon == funPtrTyConKey ->+                 IsFunction+             _ -> IsData+   (_resTy, foRhs) <- jsResultWrapper ty+--   ASSERT(fromJust resTy `eqType` addrPrimTy)    -- typechecker ensures this+   let rhs = foRhs (Lit (LitLabel cid stdcall_info fod))+       rhs' = Cast rhs co+       stdcall_info = fun_type_arg_stdcall_info cconv ty++   return ([(id, rhs')], mempty, mempty)++dsJsImport id co (CFunction target) cconv@PrimCallConv safety _+  = dsPrimCall id co (CCall (CCallSpec target cconv safety))+dsJsImport id co (CFunction target) cconv safety mHeader+  = dsJsCall id co (CCall (CCallSpec target cconv safety)) mHeader+dsJsImport id co CWrapper cconv _ _+  = dsJsFExportDynamic id co cconv++-- fixme work in progress+-- FIXME (Sylvain 2022-03): possibility of code sharing with dsFExportDynamic?+-- Lot of duplication+dsJsFExportDynamic :: Id+                 -> Coercion+                 -> CCallConv+                 -> DsM ([Binding], CHeader, CStub)+dsJsFExportDynamic id co0 cconv = do+    let+      ty                            = pFst (coercionKind co0)+      (tvs,sans_foralls)            = tcSplitForAllTyVars ty+      ([Scaled arg_mult arg_ty], fn_res_ty)  = tcSplitFunTys sans_foralls+      (io_tc, res_ty)               = expectJust "dsJsFExportDynamic: IO type expected"+                                        -- Must have an IO type; hence Just+                                        $ tcSplitIOType_maybe fn_res_ty+    mod <- getModule+    platform <- targetPlatform <$> getDynFlags+    let fe_nm = mkFastString $ zEncodeString+            ("h$" ++ moduleStableString mod ++ "$" ++ toJsName id)+        -- Construct the label based on the passed id, don't use names+        -- depending on Unique. See #13807 and Note [Unique Determinism].+    cback <- newSysLocalDs arg_mult arg_ty+    newStablePtrId <- dsLookupGlobalId newStablePtrName+    stable_ptr_tycon <- dsLookupTyCon stablePtrTyConName+    let+        stable_ptr_ty = mkTyConApp stable_ptr_tycon [arg_ty]+        export_ty     = mkVisFunTyMany stable_ptr_ty arg_ty+    bindIOId <- dsLookupGlobalId bindIOName+    stbl_value <- newSysLocalDs ManyTy stable_ptr_ty+    (h_code, c_code, typestring, args_size) <- dsJsFExport id (mkRepReflCo export_ty) fe_nm cconv True+    let+         {-+          The arguments to the external function which will+          create a little bit of (template) code on the fly+          for allowing the (stable pointed) Haskell closure+          to be entered using an external calling convention+          (stdcall, ccall).+         -}+        adj_args      = [ mkIntLit platform (toInteger (ccallConvToInt cconv))+                        , Var stbl_value+                        , Lit (LitLabel fe_nm mb_sz_args IsFunction)+                        , Lit (mkLitString typestring)+                        ]+          -- name of external entry point providing these services.+          -- (probably in the RTS.)+        adjustor   = fsLit "createAdjustor"++          -- Determine the number of bytes of arguments to the stub function,+          -- so that we can attach the '@N' suffix to its label if it is a+          -- stdcall on Windows.+        mb_sz_args = case cconv of+                        StdCallConv -> Just args_size+                        _           -> Nothing++    ccall_adj <- dsCCall adjustor adj_args PlayRisky (mkTyConApp io_tc [res_ty])+        -- PlayRisky: the adjustor doesn't allocate in the Haskell heap or do a callback++    let io_app = mkLams tvs                  $+                 Lam cback                   $+                 mkApps (Var bindIOId)+                        [ Type stable_ptr_ty+                        , Type res_ty+                        , mkApps (Var newStablePtrId) [ Type arg_ty, Var cback ]+                        , Lam stbl_value ccall_adj+                        ]++        fed = (id `setInlineActivation` NeverActive, Cast io_app co0)+               -- Never inline the f.e.d. function, because the litlit+               -- might not be in scope in other modules.++    return ([fed], h_code, c_code)++toJsName :: Id -> String+toJsName i = renderWithContext defaultSDocContext (pprCode (ppr (idName i)))++dsJsCall :: Id -> Coercion -> ForeignCall -> Maybe Header+        -> DsM ([(Id, Expr TyVar)], CHeader, CStub)+dsJsCall fn_id co (CCall (CCallSpec target cconv safety)) _mDeclHeader = do+    let+        ty                   = pFst $ coercionKind co+        (tv_bndrs, rho)      = tcSplitForAllTyVarBinders ty+        (arg_tys, io_res_ty) = tcSplitFunTys rho++    args <- newSysLocalsDs arg_tys  -- no FFI levity-polymorphism+    (val_args, arg_wrappers) <- mapAndUnzipM unboxJsArg (map Var args)++    let+        work_arg_ids  = [v | Var v <- val_args] -- All guaranteed to be vars++    (ccall_result_ty, res_wrapper) <- boxJsResult io_res_ty++    ccall_uniq <- newUnique+    work_uniq  <- newUnique++    simpl_opts <- initSimpleOpts <$> getDynFlags++    let+        -- Build the worker+        fcall         = CCall (CCallSpec target cconv safety)+        worker_ty     = mkForAllTys tv_bndrs (mkVisFunTysMany (map idType work_arg_ids) ccall_result_ty)+        tvs           = map binderVar tv_bndrs+        the_ccall_app = mkFCall ccall_uniq fcall val_args ccall_result_ty+        work_rhs      = mkLams tvs (mkLams work_arg_ids the_ccall_app)+        work_id       = mkSysLocal (fsLit "$wccall") work_uniq ManyTy worker_ty++        -- Build the wrapper+        work_app     = mkApps (mkVarApps (Var work_id) tvs) val_args+        wrapper_body = foldr ($) (res_wrapper work_app) arg_wrappers+        wrap_rhs     = mkLams (tvs ++ args) wrapper_body+        wrap_rhs'    = Cast wrap_rhs co+        fn_id_w_inl  = fn_id+                       `setIdUnfolding`+                       mkInlineUnfoldingWithArity simpl_opts VanillaSrc+                                                  (length args)  wrap_rhs'++    return ([(work_id, work_rhs), (fn_id_w_inl, wrap_rhs')], mempty, mempty)+++mkHObj :: Type -> SDoc+mkHObj t = text "h$rts_mk" <> text (showFFIType t)++unpackHObj :: Type -> SDoc+unpackHObj t = text "h$rts_get" <> text (showFFIType t)++showStgType :: Type -> SDoc+showStgType t = text "Hs" <> text (showFFIType t)++showFFIType :: Type -> String+showFFIType t = getOccString (getName (typeTyCon t))++typeTyCon :: Type -> TyCon+typeTyCon ty+  -- UnaryRep rep_ty <- repType ty+  | Just (tc, _) <- tcSplitTyConApp_maybe (unwrapType ty) -- rep_ty+  = tc+  | otherwise+  = pprPanic "typeTyCon" (ppr ty)+++{-+  We unbox arguments for JS calls a bit different from native code:+    - Bool is marshalled to true/false, not 0/1+    - All int types are narrowed, since JS floats have a greater range than Int32+ -}++unboxJsArg :: CoreExpr                  -- The supplied argument+           -> DsM (CoreExpr,              -- To pass as the actual argument+                   CoreExpr -> CoreExpr   -- Wrapper to unbox the arg+                  )+unboxJsArg arg+  -- Primtive types: nothing to unbox+  | isPrimitiveType arg_ty+  = return (arg, \body -> body)++  -- Recursive newtypes+  | Just (co, _rep_ty) <- topNormaliseNewType_maybe arg_ty+  = unboxJsArg (mkCast arg co)++  -- Booleans, do not convert to 0/1, only force them+  | Just tc <- tyConAppTyCon_maybe arg_ty,+    tc `hasKey` boolTyConKey+  = return (arg,+              \ body -> mkWildCase arg (unrestricted boolTy) (exprType body) [Alt DEFAULT [] body])++  | Just tc <- tyConAppTyCon_maybe arg_ty,+    tc `hasKey` anyTyConKey+  = return (arg,+              \ body -> mkWildCase arg (unrestricted arg_ty) (exprType body) [Alt DEFAULT [] body])+  -- Data types with a single constructor, which has a single, primitive-typed arg+  -- This deals with Int, Float etc; also Ptr, ForeignPtr+  | is_product_type && data_con_arity == 1+    = do case_bndr <- newSysLocalDs ManyTy arg_ty+         prim_arg <- newSysLocalDs ManyTy (scaledThing data_con_arg_ty1)+         return (Var prim_arg,+               \ body -> Case arg case_bndr (exprType body) [Alt (DataAlt data_con) [prim_arg] body]+              )++  -- Byte-arrays, both mutable and otherwise; hack warning+  -- We're looking for values of type ByteArray, MutableByteArray+  --    data ByteArray          ix = ByteArray        ix ix ByteArray#+  --    data MutableByteArray s ix = MutableByteArray ix ix (MutableByteArray# s)+  | is_product_type &&+    data_con_arity == 3 &&+    isJust maybe_arg3_tycon &&+    (arg3_tycon ==  byteArrayPrimTyCon ||+     arg3_tycon ==  mutableByteArrayPrimTyCon)+  = do case_bndr <- newSysLocalDs ManyTy arg_ty+       vars@[_l_var, _r_var, arr_cts_var] <- newSysLocalsDs data_con_arg_tys+       return (Var arr_cts_var,+               \ body -> Case arg case_bndr (exprType body) [Alt (DataAlt data_con) vars body]+              )++  | otherwise+  = do l <- getSrcSpanDs+       pprPanic "unboxJsArg: " (ppr l <+> ppr arg_ty)+  where+    arg_ty                                      = exprType arg+    maybe_product_type                          = splitDataProductType_maybe arg_ty+    is_product_type                             = isJust maybe_product_type+    Just (_, _, data_con, data_con_arg_tys)     = maybe_product_type+    data_con_arity                              = dataConSourceArity data_con+    (data_con_arg_ty1 : _)                      = data_con_arg_tys++    (_ : _ : data_con_arg_ty3 : _) = data_con_arg_tys+    maybe_arg3_tycon               = tyConAppTyCon_maybe (scaledThing data_con_arg_ty3)+    Just arg3_tycon                = maybe_arg3_tycon+++boxJsResult :: Type+            -> DsM (Type, CoreExpr -> CoreExpr)+boxJsResult result_ty+  | isRuntimeRepKindedTy result_ty = panic "boxJsResult: runtime rep ty" -- fixme+-- Takes the result of the user-level ccall:+--      either (IO t),+--      or maybe just t for an side-effect-free call+-- Returns a wrapper for the primitive ccall itself, along with the+-- type of the result of the primitive ccall.  This result type+-- will be of the form+--      State# RealWorld -> (# State# RealWorld, t' #)+-- where t' is the unwrapped form of t.  If t is simply (), then+-- the result type will be+--      State# RealWorld -> (# State# RealWorld #)++boxJsResult result_ty+  | Just (io_tycon, io_res_ty) <- tcSplitIOType_maybe result_ty+        -- isIOType_maybe handles the case where the type is a+        -- simple wrapping of IO.  E.g.+        --      newtype Wrap a = W (IO a)+        -- No coercion necessary because its a non-recursive newtype+        -- (If we wanted to handle a *recursive* newtype too, we'd need+        -- another case, and a coercion.)+        -- The result is IO t, so wrap the result in an IO constructor+  = do  { res <- jsResultWrapper io_res_ty+        ; let return_result state ans+                = mkCoreUnboxedTuple [state, ans]++        ; (ccall_res_ty, the_alt) <- mk_alt return_result res++        ; state_id <- newSysLocalDs ManyTy realWorldStatePrimTy+        ; let io_data_con = head (tyConDataCons io_tycon)+              toIOCon     = dataConWrapId io_data_con++              wrap the_call =+                              mkApps (Var toIOCon)+                                     [ Type io_res_ty,+                                       Lam state_id $+                                       mkWildCase (App the_call (Var state_id))+                                             (unrestricted ccall_res_ty)+                                             (coreAltType the_alt)+                                             [the_alt]+                                     ]++        ; return (realWorldStatePrimTy `mkVisFunTyMany` ccall_res_ty, wrap) }++boxJsResult result_ty+  = do -- It isn't IO, so do unsafePerformIO+       -- It's not conveniently available, so we inline it+       res <- jsResultWrapper result_ty+       (ccall_res_ty, the_alt) <- mk_alt return_result res+       let+           wrap = \ the_call -> mkWildCase (App the_call (Var realWorldPrimId))+                                           (unrestricted ccall_res_ty)+                                           (coreAltType the_alt)+                                           [the_alt]+       return (realWorldStatePrimTy `mkVisFunTyMany` ccall_res_ty, wrap)+  where+    return_result _ ans = ans++mk_alt :: (Expr Var -> Expr Var -> Expr Var)+       -> (Maybe Type, Expr Var -> Expr Var)+       -> DsM (Type, CoreAlt)+mk_alt return_result (Nothing, wrap_result)+  = do -- The ccall returns ()+       state_id <- newSysLocalDs ManyTy realWorldStatePrimTy+       let+             the_rhs = return_result (Var state_id)+                                     (wrap_result $ panic "jsBoxResult")+             ccall_res_ty = mkTupleTy Unboxed [realWorldStatePrimTy]+             the_alt      = Alt (DataAlt (tupleDataCon Unboxed 1)) [state_id] the_rhs+       return (ccall_res_ty, the_alt)++mk_alt return_result (Just prim_res_ty, wrap_result)+                -- The ccall returns a non-() value+  | isUnboxedTupleType prim_res_ty = do+    let+        Just ls = fmap dropRuntimeRepArgs (tyConAppArgs_maybe prim_res_ty)+        arity = 1 + length ls+    args_ids <- mapM (newSysLocalDs ManyTy) ls+    state_id <- newSysLocalDs ManyTy realWorldStatePrimTy+    let+        result_tup = mkCoreUnboxedTuple (map Var args_ids)+        the_rhs = return_result (Var state_id)+                                (wrap_result result_tup)+        ccall_res_ty = mkTupleTy Unboxed (realWorldStatePrimTy : ls)+        the_alt      = Alt (DataAlt (tupleDataCon Unboxed arity))+                           (state_id : args_ids)+                          the_rhs+    return (ccall_res_ty, the_alt)++  | otherwise = do+    result_id <- newSysLocalDs ManyTy prim_res_ty+    state_id <- newSysLocalDs ManyTy realWorldStatePrimTy+    let+        the_rhs = return_result (Var state_id)+                                (wrap_result (Var result_id))+        ccall_res_ty = mkTupleTy Unboxed [realWorldStatePrimTy, prim_res_ty]+        the_alt      = Alt (DataAlt (tupleDataCon Unboxed 2)) [state_id, result_id] the_rhs+    return (ccall_res_ty, the_alt)++fun_type_arg_stdcall_info :: CCallConv -> Type -> Maybe Int+fun_type_arg_stdcall_info _other_conv _ = Nothing+++jsResultWrapper+  :: Type+  -> DsM ( Maybe Type           -- Type of the expected result, if any+         , CoreExpr -> CoreExpr -- Wrapper for the result+         )+-- resultWrapper deals with the result *value*+-- E.g. foreign import foo :: Int -> IO T+-- Then resultWrapper deals with marshalling the 'T' part+jsResultWrapper result_ty+  | isRuntimeRepKindedTy result_ty = return (Nothing, id) -- fixme this seems like a hack+  -- Base case 1a: unboxed tuples+  | Just (tc, args) <- splitTyConApp_maybe result_ty+  , isUnboxedTupleTyCon tc {- && False -} = do+    let args' = dropRuntimeRepArgs args+    (tys, wrappers) <- unzip <$> mapM jsResultWrapper args'+    matched <- mapM (mapM (newSysLocalDs ManyTy)) tys+    let tys'    = catMaybes tys+        -- arity   = length args'+        -- resCon  = tupleDataCon Unboxed (length args)+        err     = panic "jsResultWrapper: used Id with result type Nothing"+        resWrap :: CoreExpr+        resWrap = mkCoreUnboxedTuple (zipWith (\w -> w . Var . fromMaybe err) wrappers matched)+    return $+      if null tys'+        then (Nothing, \_ -> resWrap)+        else let innerArity = length tys'+                 innerTy    = mkTupleTy Unboxed tys'+                 innerCon   = tupleDataCon Unboxed innerArity+                 inner :: CoreExpr -> CoreExpr+                 inner e    = mkWildCase e (unrestricted innerTy) result_ty+                                         [Alt (DataAlt innerCon)+                                              (catMaybes matched)+                                              resWrap+                                         ]+             in (Just innerTy, inner)++  -- Base case 1b: primitive types+  | isPrimitiveType result_ty+  = return (Just result_ty, \e -> e)+  -- Base case 1c: boxed tuples+  -- fixme: levity args?+  | Just (tc, args) <- splitTyConApp_maybe result_ty+  , isBoxedTupleTyCon tc = do+      let args'   = dropRuntimeRepArgs args+          innerTy = mkTupleTy Unboxed args'+      (inner_res, w) <- jsResultWrapper innerTy+      matched <- mapM (newSysLocalDs ManyTy) args'+      let inner e = mkWildCase (w e) (unrestricted innerTy) result_ty+                               [ Alt (DataAlt (tupleDataCon Unboxed (length args')))+                                     matched+                                     (mkCoreTup (map Var matched))+                                -- mkCoreConApps (tupleDataCon Boxed (length args)) (map Type args ++ map Var matched)+                               ]+      return (inner_res, inner)++  -- Base case 2: the unit type ()+  | Just (tc,_) <- maybe_tc_app, tc `hasKey` unitTyConKey+  = return (Nothing, \_ -> Var unitDataConId)++  -- Base case 3: the boolean type+  | Just (tc,_) <- maybe_tc_app, tc `hasKey` boolTyConKey = do+--    result_id <- newSysLocalDs boolTy+    ccall_uniq <- newUnique+    let forceBool e = mkJsCall ccall_uniq "$r = !(!$1)" [e] boolTy+    return+     (Just intPrimTy, \e -> forceBool e)++  -- Base case 4: the any type+  |  Just (tc,_) <- maybe_tc_app, tc `hasKey` anyTyConKey+  = return (Just result_ty, \e -> e)++  -- Newtypes+  | Just (co, rep_ty) <- topNormaliseNewType_maybe result_ty+  = do (maybe_ty, wrapper) <- jsResultWrapper rep_ty+       return (maybe_ty, \e -> mkCastDs (wrapper e) (mkSymCo co))++  -- The type might contain foralls (eg. for dummy type arguments,+  -- referring to 'Ptr a' is legal).+  | Just (tyvar, rest) <- splitForAllTyCoVar_maybe result_ty+  = do (maybe_ty, wrapper) <- jsResultWrapper rest+       return (maybe_ty, \e -> Lam tyvar (wrapper e))++  -- Data types with a single constructor, which has a single arg+  -- This includes types like Ptr and ForeignPtr+  | Just (_tycon, tycon_arg_tys, data_con, data_con_arg_tys) <- splitDataProductType_maybe result_ty,+    dataConSourceArity data_con == 1+  = do let (unwrapped_res_ty : _) = data_con_arg_tys+       (maybe_ty, wrapper) <- jsResultWrapper (scaledThing unwrapped_res_ty)+       return+         (maybe_ty, \e -> mkApps (Var (dataConWrapId data_con))+                                 (map Type tycon_arg_tys ++ [wrapper e]))++  | otherwise+  = pprPanic "jsResultWrapper" (ppr result_ty)+  where+    maybe_tc_app = splitTyConApp_maybe result_ty++-- low-level primitive JavaScript call:+mkJsCall :: Unique -> String -> [CoreExpr] -> Type -> CoreExpr+mkJsCall u tgt args t = mkFCall u ccall args t+  where+    ccall = CCall $ CCallSpec+              (StaticTarget NoSourceText (mkFastString tgt) (Just primUnit) True)+              JavaScriptCallConv+              PlayRisky
compiler/GHC/HsToCore/GuardedRHSs.hs view
@@ -129,7 +129,7 @@  matchGuards (BindStmt _ pat bind_rhs : stmts) ctx nablas rhs rhs_ty = do     let upat = unLoc pat-    match_var <- selectMatchVar Many upat+    match_var <- selectMatchVar ManyTy upat        -- We only allow unrestricted patterns in guard, hence the `Many`        -- above. It isn't clear what linear patterns would mean, maybe we will        -- figure it out in the future.
compiler/GHC/HsToCore/ListComp.hs view
@@ -366,8 +366,8 @@     let b_ty   = idType n_id      -- create some new local id's-    b <- newSysLocalDs Many b_ty-    x <- newSysLocalDs Many x_ty+    b <- newSysLocalDs ManyTy b_ty+    x <- newSysLocalDs ManyTy x_ty      -- build rest of the comprehension     core_rest <- dfListComp c_id b quals@@ -397,11 +397,11 @@ --                              (a2:as'2) -> (a1, a2) : zip as'1 as'2)]  mkZipBind elt_tys = do-    ass  <- mapM (newSysLocalDs Many)  elt_list_tys-    as'  <- mapM (newSysLocalDs Many)  elt_tys-    as's <- mapM (newSysLocalDs Many)  elt_list_tys+    ass  <- mapM (newSysLocalDs ManyTy)  elt_list_tys+    as'  <- mapM (newSysLocalDs ManyTy)  elt_tys+    as's <- mapM (newSysLocalDs ManyTy)  elt_list_tys -    zip_fn <- newSysLocalDs Many zip_fn_ty+    zip_fn <- newSysLocalDs ManyTy zip_fn_ty      let inner_rhs = mkConsExpr elt_tuple_ty                         (mkBigCoreVarTup as')@@ -436,13 +436,13 @@ mkUnzipBind ThenForm _  = return Nothing    -- No unzipping for ThenForm mkUnzipBind _ elt_tys-  = do { ax  <- newSysLocalDs Many elt_tuple_ty-       ; axs <- newSysLocalDs Many elt_list_tuple_ty-       ; ys  <- newSysLocalDs Many elt_tuple_list_ty-       ; xs  <- mapM (newSysLocalDs Many) elt_tys-       ; xss <- mapM (newSysLocalDs Many) elt_list_tys+  = do { ax  <- newSysLocalDs ManyTy elt_tuple_ty+       ; axs <- newSysLocalDs ManyTy elt_list_tuple_ty+       ; ys  <- newSysLocalDs ManyTy elt_tuple_list_ty+       ; xs  <- mapM (newSysLocalDs ManyTy) elt_tys+       ; xss <- mapM (newSysLocalDs ManyTy) elt_list_tys -       ; unzip_fn <- newSysLocalDs Many unzip_fn_ty+       ; unzip_fn <- newSysLocalDs ManyTy unzip_fn_ty         ; [us1, us2] <- sequence [newUniqueSupply, newUniqueSupply] @@ -450,8 +450,8 @@              concat_expressions = map mkConcatExpression (zip3 elt_tys (map Var xs) (map Var xss))              tupled_concat_expression = mkBigCoreTup concat_expressions -             folder_body_inner_case = mkTupleCase us1 xss tupled_concat_expression axs (Var axs)-             folder_body_outer_case = mkTupleCase us2 xs folder_body_inner_case ax (Var ax)+             folder_body_inner_case = mkBigTupleCase us1 xss tupled_concat_expression (Var axs)+             folder_body_outer_case = mkBigTupleCase us2 xs folder_body_inner_case (Var ax)              folder_body = mkLams [ax, axs] folder_body_outer_case         ; unzip_body <- mkFoldrExpr elt_tuple_ty elt_list_tuple_ty folder_body nil_tuple (Var ys)@@ -543,15 +543,12 @@        -- Generate the expressions to build the grouped list        -- Build a pattern that ensures the consumer binds into the NEW binders,        -- which hold monads rather than single values-       ; let tup_n_ty' = mkBigCoreVarTupTy to_bndrs-        ; body        <- dsMcStmts stmts_rest-       ; n_tup_var'  <- newSysLocalDs Many n_tup_ty'-       ; tup_n_var'  <- newSysLocalDs Many tup_n_ty'+       ; n_tup_var'  <- newSysLocalDs ManyTy n_tup_ty'        ; tup_n_expr' <- mkMcUnzipM form fmap_op n_tup_var' from_bndr_tys        ; us          <- newUniqueSupply        ; let rhs'  = mkApps usingExpr' usingArgs'-             body' = mkTupleCase us to_bndrs body tup_n_var' tup_n_expr'+             body' = mkBigTupleCase us to_bndrs body tup_n_expr'         ; dsSyntaxExpr bind_op [rhs', Lam n_tup_var' body'] } @@ -596,8 +593,8 @@ --  \x. case x of (a,b,c) -> body matchTuple ids body   = do { us <- newUniqueSupply-       ; tup_id <- newSysLocalDs Many (mkBigCoreVarTupTy ids)-       ; return (Lam tup_id $ mkTupleCase us ids body tup_id (Var tup_id)) }+       ; tup_id <- newSysLocalDs ManyTy (mkBigCoreVarTupTy ids)+       ; return (Lam tup_id $ mkBigTupleCase us ids body (Var tup_id)) }  -- general `rhs' >>= \pat -> stmts` desugaring where `rhs'` is already a -- desugared `CoreExpr`@@ -610,7 +607,7 @@              -> DsM CoreExpr dsMcBindStmt pat rhs' bind_op fail_op res1_ty stmts   = do  { body     <- dsMcStmts stmts-        ; var      <- selectSimpleMatchVarL Many pat+        ; var      <- selectSimpleMatchVarL ManyTy pat         ; match <- matchSinglePatVar var Nothing (StmtCtxt (HsDoStmt (DoExpr Nothing))) pat                                   res1_ty (cantFailMatchResult body)         ; match_code <- dsHandleMonadicFailure MonadComp pat match fail_op@@ -651,15 +648,15 @@  mkMcUnzipM _ fmap_op ys elt_tys   = do { fmap_op' <- dsExpr fmap_op-       ; xs       <- mapM (newSysLocalDs Many) elt_tys+       ; xs       <- mapM (newSysLocalDs ManyTy) elt_tys        ; let tup_ty = mkBigCoreTupTy elt_tys-       ; tup_xs   <- newSysLocalDs Many tup_ty+       ; tup_xs   <- newSysLocalDs ManyTy tup_ty         ; let mk_elt i = mkApps fmap_op'  -- fmap :: forall a b. (a -> b) -> n a -> n b                            [ Type tup_ty, Type (getNth elt_tys i)                            , mk_sel i, Var ys]               mk_sel n = Lam tup_xs $-                        mkTupleSelector xs (getNth xs n) tup_xs (Var tup_xs)+                        mkBigTupleSelector xs (getNth xs n) tup_xs (Var tup_xs)         ; return (mkBigCoreTup (map mk_elt [0..length elt_tys - 1])) }
compiler/GHC/HsToCore/Match.hs view
@@ -6,7 +6,6 @@ {-# LANGUAGE ViewPatterns #-}  {-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}-{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}  {- (c) The University of Glasgow 2006@@ -38,27 +37,31 @@ import GHC.Tc.Utils.Monad import GHC.HsToCore.Pmc import GHC.HsToCore.Pmc.Types ( Nablas, initNablas )-import GHC.Core-import GHC.Types.Literal-import GHC.Core.Utils-import GHC.Core.Make import GHC.HsToCore.Monad import GHC.HsToCore.Binds import GHC.HsToCore.GuardedRHSs import GHC.HsToCore.Utils-import GHC.Types.Id-import GHC.Core.ConLike-import GHC.Core.DataCon-import GHC.Core.PatSyn import GHC.HsToCore.Errors.Types import GHC.HsToCore.Match.Constructor import GHC.HsToCore.Match.Literal++import GHC.Core+import GHC.Core.Utils+import GHC.Core.Make+import GHC.Core.ConLike+import GHC.Core.DataCon+import GHC.Core.PatSyn import GHC.Core.Type+import GHC.Core.TyCo.Compare( eqType, eqTypes ) import GHC.Core.Coercion ( eqCoercion ) import GHC.Core.TyCon    ( isNewTyCon ) import GHC.Core.Multiplicity import GHC.Builtin.Types++import GHC.Types.Id+import GHC.Types.Literal import GHC.Types.SrcLoc+ import GHC.Data.Maybe import GHC.Utils.Misc import GHC.Types.Name@@ -871,7 +874,7 @@   = matchSinglePatVar var Nothing ctx pat ty match_result  matchSinglePat scrut hs_ctx pat ty match_result-  = do { var           <- selectSimpleMatchVarL Many pat+  = do { var           <- selectSimpleMatchVarL ManyTy pat                             -- matchSinglePat is only used in matchSimply, which                             -- is used in list comprehension, arrow notation,                             -- and to create field selectors. All of which only
compiler/GHC/HsToCore/Match/Literal.hs view
@@ -36,29 +36,36 @@  import GHC.Hs -import GHC.Types.Id-import GHC.Types.SourceText+import GHC.Tc.Utils.Zonk ( shortCutLit )+import GHC.Tc.Utils.TcType+ import GHC.Core import GHC.Core.Make import GHC.Core.TyCon import GHC.Core.Reduction ( Reduction(..) ) import GHC.Core.DataCon-import GHC.Tc.Utils.Zonk ( shortCutLit )-import GHC.Tc.Utils.TcType-import GHC.Types.Name import GHC.Core.Type+import GHC.Core.FamInstEnv ( FamInstEnvs, normaliseType )++import GHC.Types.Name+import GHC.Types.Literal+import GHC.Types.SrcLoc+ import GHC.Builtin.Names import GHC.Builtin.Types import GHC.Builtin.Types.Prim-import GHC.Types.Literal-import GHC.Types.SrcLoc-import GHC.Utils.Outputable as Outputable++import GHC.Types.Id+import GHC.Types.SourceText+ import GHC.Driver.Session++import GHC.Utils.Outputable as Outputable import GHC.Utils.Misc import GHC.Utils.Panic import GHC.Utils.Panic.Plain+ import GHC.Data.FastString-import GHC.Core.FamInstEnv ( FamInstEnvs, normaliseType )  import Control.Monad import Data.Int@@ -265,7 +272,7 @@ warnAboutIdentities dflags conv_fn type_of_conv   | wopt Opt_WarnIdentities dflags   , idName conv_fn `elem` conversionNames-  , Just (_, arg_ty, res_ty) <- splitFunTy_maybe type_of_conv+  , Just (_, _, arg_ty, res_ty) <- splitFunTy_maybe type_of_conv   , arg_ty `eqType` res_ty  -- So we are converting  ty -> ty   = diagnosticDs (DsIdentitiesFound conv_fn type_of_conv) warnAboutIdentities _ _ _ = return ()
compiler/GHC/HsToCore/Monad.hs view
@@ -23,7 +23,7 @@         newSysLocalsDs, newUniqueId,         newFailLocalDs, newPredVarDs,         getSrcSpanDs, putSrcSpanDs, putSrcSpanDsA,-        mkPrintUnqualifiedDs,+        mkNamePprCtxDs,         newUnique,         UniqSupply, newUniqueSupply,         getGhcModeDs, dsGetFamInstEnvs,@@ -199,7 +199,7 @@  type DsWarning = (SrcSpan, SDoc)         -- Not quite the same as a WarnMsg, we have an SDoc here-        -- and we'll do the print_unqual stuff later on to turn it+        -- and we'll do the name_ppr_ctx stuff later on to turn it         -- into a Doc.  -- | Run a 'DsM' action inside the 'TcM' monad.@@ -237,12 +237,13 @@              type_env = tcg_type_env tcg_env              rdr_env  = tcg_rdr_env tcg_env              fam_inst_env = tcg_fam_inst_env tcg_env+             ptc = initPromotionTickContext (hsc_dflags hsc_env)              complete_matches = hptCompleteSigs hsc_env         -- from the home package                                 ++ tcg_complete_matches tcg_env -- from the current module                                 ++ eps_complete_matches eps     -- from imports              -- re-use existing next_wrapper_num to ensure uniqueness              next_wrapper_num_var = tcg_next_wrapper_num tcg_env-       ; return $ mkDsEnvs unit_env this_mod rdr_env type_env fam_inst_env+       ; return $ mkDsEnvs unit_env this_mod rdr_env type_env fam_inst_env ptc                            msg_var cc_st_var next_wrapper_num_var complete_matches        } @@ -272,6 +273,7 @@        ; eps <- liftIO $ hscEPS hsc_env        ; let unit_env = hsc_unit_env hsc_env              type_env = typeEnvFromEntities ids tycons patsyns fam_insts+             ptc = initPromotionTickContext (hsc_dflags hsc_env)              complete_matches = hptCompleteSigs hsc_env     -- from the home package                                 ++ local_complete_matches  -- from the current module                                 ++ eps_complete_matches eps -- from imports@@ -281,7 +283,7 @@              ids = concatMap bindsToIds binds               envs  = mkDsEnvs unit_env this_mod rdr_env type_env-                              fam_inst_env msg_var cc_st_var+                              fam_inst_env ptc msg_var cc_st_var                               next_wrapper_num complete_matches        ; runDs hsc_env envs thing_inside        }@@ -320,10 +322,11 @@            Nothing  -> pprPanic "initTcDsForSolver" (vcat $ pprMsgEnvelopeBagWithLocDefault (getErrorMessages msgs)) }  mkDsEnvs :: UnitEnv -> Module -> GlobalRdrEnv -> TypeEnv -> FamInstEnv+         -> PromotionTickContext          -> IORef (Messages DsMessage) -> IORef CostCentreState          -> IORef (ModuleEnv Int) -> CompleteMatches          -> (DsGblEnv, DsLclEnv)-mkDsEnvs unit_env mod rdr_env type_env fam_inst_env msg_var cc_st_var+mkDsEnvs unit_env mod rdr_env type_env fam_inst_env ptc msg_var cc_st_var          next_wrapper_num complete_matches   = let if_genv = IfGblEnv { if_doc       = text "mkDsEnvs"   -- Failing tests here are `ghci` and `T11985` if you get this wrong.@@ -340,7 +343,7 @@                            , ds_fam_inst_env = fam_inst_env                            , ds_gbl_rdr_env  = rdr_env                            , ds_if_env  = (if_genv, if_lenv)-                           , ds_unqual  = mkPrintUnqualified unit_env rdr_env+                           , ds_name_ppr_ctx = mkNamePprCtx ptc unit_env rdr_env                            , ds_msgs    = msg_var                            , ds_complete_matches = complete_matches                            , ds_cc_st   = cc_st_var@@ -378,7 +381,7 @@  newPredVarDs :: PredType -> DsM Var newPredVarDs- = mkSysLocalOrCoVarM (fsLit "ds") Many  -- like newSysLocalDs, but we allow covars+ = mkSysLocalOrCoVarM (fsLit "ds") ManyTy  -- like newSysLocalDs, but we allow covars  newSysLocalDs, newFailLocalDs :: Mult -> Type -> DsM Id newSysLocalDs = mkSysLocalM (fsLit "ds")@@ -425,7 +428,7 @@   = do { env <- getGblEnv        ; loc <- getSrcSpanDs        ; !diag_opts <- initDiagOpts <$> getDynFlags-       ; let msg = mkMsgEnvelope diag_opts loc (ds_unqual env) dsMessage+       ; let msg = mkMsgEnvelope diag_opts loc (ds_name_ppr_ctx env) dsMessage        ; updMutVar (ds_msgs env) (\ msgs -> msg `addMessage` msgs) }  -- | Issue an error, but return the expression for (), so that we can continue@@ -443,8 +446,8 @@ failDs :: DsM a failDs = failM -mkPrintUnqualifiedDs :: DsM PrintUnqualified-mkPrintUnqualifiedDs = ds_unqual <$> getGblEnv+mkNamePprCtxDs :: DsM NamePprCtx+mkNamePprCtxDs = ds_name_ppr_ctx <$> getGblEnv  instance MonadThings (IOEnv (Env DsGblEnv DsLclEnv)) where     lookupThing = dsLookupGlobal
compiler/GHC/HsToCore/Pmc/Desugar.hs view
@@ -42,6 +42,7 @@ import GHC.HsToCore.Match.Literal (dsLit, dsOverLit) import GHC.HsToCore.Monad import GHC.Core.TyCo.Rep+import GHC.Core.TyCo.Compare( eqType ) import GHC.Core.Type import GHC.Data.Maybe import qualified GHC.LanguageExtensions as LangExt@@ -139,7 +140,8 @@         ListPat {}           | ViewPat arg_ty _lexpr pat <- expansion           , not (xopt LangExt.RebindableSyntax dflags)-          , Just _ <- splitListTyConApp_maybe arg_ty+          , Just tc <- tyConAppTyCon_maybe arg_ty+          , tc == listTyCon           -> desugarLPat x pat          _ -> desugarPat x expansion@@ -247,7 +249,7 @@ -- | 'desugarPat', but also select and return a new match var. desugarPatV :: Pat GhcTc -> DsM (Id, [PmGrd]) desugarPatV pat = do-  x <- selectMatchVar Many pat+  x <- selectMatchVar ManyTy pat   grds <- desugarPat x pat   pure (x, grds) 
compiler/GHC/HsToCore/Pmc/Solver.hs view
@@ -45,6 +45,7 @@ import GHC.Utils.Panic import GHC.Utils.Panic.Plain import GHC.Data.Bag+ import GHC.Types.Basic (Levity(..)) import GHC.Types.CompleteMatch import GHC.Types.Unique.Set@@ -55,14 +56,17 @@ import GHC.Types.Var      (EvVar) import GHC.Types.Var.Env import GHC.Types.Var.Set+import GHC.Types.Unique.Supply+ import GHC.Core-import GHC.Core.FVs       (exprFreeVars)+import GHC.Core.FVs         (exprFreeVars)+import GHC.Core.TyCo.Compare( eqType ) import GHC.Core.Map.Expr import GHC.Core.Predicate (typeDeterminesValue) import GHC.Core.SimpleOpt (simpleOptExpr, exprIsConApp_maybe) import GHC.Core.Utils     (exprType) import GHC.Core.Make      (mkListExpr, mkCharExpr, mkRuntimeErrorApp, rUNTIME_ERROR_ID)-import GHC.Types.Unique.Supply+ import GHC.Data.FastString import GHC.Types.SrcLoc import GHC.Data.Maybe@@ -73,7 +77,6 @@ import GHC.Core.TyCon.RecWalk import GHC.Builtin.Names import GHC.Builtin.Types-import GHC.Builtin.Types.Prim (tYPETyCon) import GHC.Core.TyCo.Rep import GHC.Core.TyCo.Subst (elemSubst) import GHC.Core.Type@@ -97,9 +100,6 @@ import qualified Data.List.NonEmpty as NE import Data.Ord      (comparing) -import GHC.Utils.Trace-_ = pprTrace -- to silence unused import warnings- -- -- * Main exports --@@ -642,7 +642,7 @@   unique <- getUniqueM   let occname = mkVarOccFS (fsLit ("pm_"++show unique))       idname  = mkInternalName unique occname noSrcSpan-  return (mkLocalIdOrCoVar idname Many pred_ty)+  return (mkLocalIdOrCoVar idname ManyTy pred_ty)  ----------------------------- -- ** Adding term constraints
compiler/GHC/HsToCore/Pmc/Utils.hs view
@@ -35,8 +35,8 @@ tracePm :: String -> SDoc -> DsM () tracePm herald doc = do   logger  <- getLogger-  printer <- mkPrintUnqualifiedDs-  liftIO $ putDumpFileMaybe' logger printer+  name_ppr_ctx <- mkNamePprCtxDs+  liftIO $ putDumpFileMaybe' logger name_ppr_ctx             Opt_D_dump_ec_trace "" FormatText (text herald $$ (nest 2 doc)) {-# INLINE tracePm #-}  -- see Note [INLINE conditional tracing utilities] @@ -52,7 +52,7 @@ mkPmId ty = getUniqueM >>= \unique ->   let occname = mkVarOccFS $ fsLit "pm"       name    = mkInternalName unique occname noSrcSpan-  in  return (mkLocalIdOrCoVar name Many ty)+  in  return (mkLocalIdOrCoVar name ManyTy ty) {-# NOINLINE mkPmId #-} -- We'll CPR deeply, that should be enough  -- | All warning flags that need to run the pattern match checker.
compiler/GHC/HsToCore/Quote.hs view
@@ -51,8 +51,8 @@ import GHC.Core.Class import GHC.Core.DataCon import GHC.Core.TyCon-import GHC.Core.Multiplicity ( pattern Many ) import GHC.Core+import GHC.Core.Type( pattern ManyTy, mkFunTy ) import GHC.Core.Make import GHC.Core.Utils @@ -129,8 +129,9 @@           -- the expected type           tyvars = dataConUserTyVarBinders (classDataCon cls)           expected_ty = mkInvisForAllTys tyvars $-                          mkInvisFunTyMany (mkClassPred cls (mkTyVarTys (binderVars tyvars)))-                                           (mkClassPred monad_cls (mkTyVarTys (binderVars tyvars)))+                        mkFunTy invisArgConstraintLike ManyTy+                                (mkClassPred cls (mkTyVarTys (binderVars tyvars)))+                                (mkClassPred monad_cls (mkTyVarTys (binderVars tyvars)))        massertPpr (idType monad_sel `eqType` expected_ty) (ppr monad_sel $$ ppr expected_ty) @@ -1357,10 +1358,10 @@ repTy ty@(HsQualTy {}) = repForallT ty  repTy (HsTyVar _ _ (L _ n))-  | isLiftedTypeKindTyConName n        = repTStar+  | n `hasKey` liftedTypeKindTyConKey  = repTStar   | n `hasKey` constraintKindTyConKey  = repTConstraint   | n `hasKey` unrestrictedFunTyConKey = repArrowTyCon-  | n `hasKey` funTyConKey             = repMulArrowTyCon+  | n `hasKey` fUNTyConKey             = repMulArrowTyCon   | isTvOcc occ   = do tv1 <- lookupOcc n                        repTvar tv1   | isDataOcc occ = do tc1 <- lookupOcc n@@ -2134,7 +2135,8 @@ -- -- Nevertheless, it's monadic because we have to generate nameTy mkGenSyms ns = do { var_ty <- lookupType nameTyConName-                  ; return [(nm, mkLocalId (localiseName nm) Many var_ty) | nm <- ns] }+                  ; return [ (nm, mkLocalId (localiseName nm) ManyTy var_ty)+                           | nm <- ns] }   addBinds :: [GenSymBind] -> MetaM a -> MetaM a@@ -2960,7 +2962,9 @@  repProjection :: NonEmpty FastString -> MetaM (Core (M TH.Exp)) repProjection fs = do-  MkC xs <- coreListNonEmpty stringTy <$> mapM coreStringLit fs+  ne_tycon <- lift $ dsLookupTyCon nonEmptyTyConName+  MkC xs <- coreListNonEmpty ne_tycon stringTy <$>+            mapM coreStringLit fs   rep2 projectionEName [xs]  ------------ Lists -------------------@@ -2992,8 +2996,13 @@           -> [Core a] -> Core [a] coreList' elt_ty es = MkC (mkListExpr elt_ty (map unC es )) -coreListNonEmpty :: Type -> NonEmpty (Core a) -> Core (NonEmpty a)-coreListNonEmpty ty (MkC x :| xs) = MkC $ mkNonEmptyListExpr ty x (map unC xs)+coreListNonEmpty :: TyCon -- TyCon for NonEmpty+                 -> Type  -- Element type+                 -> NonEmpty (Core a)+                 -> Core (NonEmpty a)+coreListNonEmpty ne_tc ty (MkC x :| xs)+  = MkC $ mkCoreConApps (tyConSingleDataCon ne_tc)+          [Type ty, x, mkListExpr ty (map unC xs)]  nonEmptyCoreList :: [Core a] -> Core [a]   -- The list must be non-empty so we can get the element type
compiler/GHC/HsToCore/Types.hs view
@@ -49,7 +49,7 @@   , ds_gbl_rdr_env  :: GlobalRdrEnv       -- needed *only* to know what newtype                                           -- constructors are in scope during                                           -- pattern-match satisfiability checking-  , ds_unqual  :: PrintUnqualified+  , ds_name_ppr_ctx :: NamePprCtx   , ds_msgs    :: IORef (Messages DsMessage) -- Diagnostic messages   , ds_if_env  :: (IfGblEnv, IfLclEnv)    -- Used for looking up global,                                           -- possibly-imported things
compiler/GHC/HsToCore/Utils.hs view
@@ -53,7 +53,6 @@  import GHC.Hs import GHC.Hs.Syn.Type-import GHC.Tc.Utils.TcType( tcSplitTyConApp ) import GHC.Core import GHC.HsToCore.Monad @@ -143,7 +142,7 @@                                   -- multiplicity stored within the variable                                   -- itself. It's easier to pull it from the                                   -- variable, so we ignore the multiplicity.-selectMatchVar _w (AsPat _ var _ _) = assert (isManyDataConTy _w ) (return (unLoc var))+selectMatchVar _w (AsPat _ var _ _) = assert (isManyTy _w ) (return (unLoc var)) selectMatchVar w other_pat        = newSysLocalDs w (hsPatType other_pat)  {- Note [Localise pattern binders]@@ -540,7 +539,7 @@     case_bndr = case arg1 of                    Var v1 | isInternalName (idName v1)                           -> v1        -- Note [Desugaring seq], points (2) and (3)-                   _      -> mkWildValBinder Many ty1+                   _      -> mkWildValBinder ManyTy ty1  mkCoreAppDs _ (Var f `App` Type _r) arg   | f `hasKey` noinlineIdKey   -- See Note [noinlineId magic] in GHC.Types.Id.Make@@ -630,7 +629,7 @@   Note that we return 't' as the variable to force if the pattern   is strict (i.e. with -XStrict or an outermost-bang-pattern) -  Note that (A) /includes/ the situation where+  Note that (C) /includes/ the situation where     * The pattern binds exactly one variable         let !(Just (Just x) = e in body@@ -640,7 +639,8 @@        in t `seq` body     The 'Solo' is a one-tuple; see Note [One-tuples] in GHC.Builtin.Types     Note that forcing 't' makes the pattern match happen,-    but does not force 'v'.+    but does not force 'v'.  That's why we call `mkBigCoreVarTupSolo`+    in `mkSeletcorBinds`    * The pattern binds no variables         let !(True,False) = e in body@@ -738,7 +738,7 @@    | is_flat_prod_lpat pat'           -- Special case (B)   = do { let pat_ty = hsLPatType pat'-       ; val_var <- newSysLocalDs Many pat_ty+       ; val_var <- newSysLocalDs ManyTy pat_ty         ; let mk_bind tick bndr_var                -- (mk_bind sv bv)  generates  bv = case sv of { pat -> bv }@@ -756,13 +756,13 @@        ; return ( val_var, (val_var, val_expr) : binds) }    | otherwise                          -- General case (C)-  = do { tuple_var  <- newSysLocalDs Many tuple_ty+  = do { tuple_var  <- newSysLocalDs ManyTy tuple_ty        ; error_expr <- mkErrorAppDs pAT_ERROR_ID tuple_ty (ppr pat')        ; tuple_expr <- matchSimply val_expr PatBindRhs pat                                    local_tuple error_expr        ; let mk_tup_bind tick binder                = (binder, mkOptTickBox tick $-                          mkTupleSelector1 local_binders binder+                          mkBigTupleSelectorSolo local_binders binder                                            tuple_var (Var tuple_var))              tup_binds = zipWith mk_tup_bind ticks' binders        ; return (tuple_var, (tuple_var, tuple_expr) : tup_binds) }@@ -775,7 +775,7 @@     ticks'  = ticks ++ repeat []      local_binders = map localiseId binders      -- See Note [Localise pattern binders]-    local_tuple   = mkBigCoreVarTup1 binders+    local_tuple   = mkBigCoreVarTupSolo binders     tuple_ty      = exprType local_tuple  strip_bangs :: LPat (GhcPass p) -> LPat (GhcPass p)@@ -913,8 +913,8 @@                       CoreExpr) -- Fail variable applied to realWorld# -- See Note [Failure thunks and CPR] mkFailurePair expr-  = do { fail_fun_var <- newFailLocalDs Many (unboxedUnitTy `mkVisFunTyMany` ty)-       ; fail_fun_arg <- newSysLocalDs Many unboxedUnitTy+  = do { fail_fun_var <- newFailLocalDs ManyTy (unboxedUnitTy `mkVisFunTyMany` ty)+       ; fail_fun_arg <- newSysLocalDs ManyTy unboxedUnitTy        ; let real_arg = setOneShotLambda fail_fun_arg        ; return (NonRec fail_fun_var (Lam real_arg expr),                  App (Var fail_fun_var) unboxedUnitExpr) }@@ -997,7 +997,7 @@ mkBinaryTickBox ixT ixF e = do        uq <- newUnique        this_mod <- getModule-       let bndr1 = mkSysLocal (fsLit "t1") uq One boolTy+       let bndr1 = mkSysLocal (fsLit "t1") uq OneTy boolTy          -- It's always sufficient to pattern-match on a boolean with          -- multiplicity 'One'.        let
compiler/GHC/Iface/Binary.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE BinaryLiterals, ScopedTypeVariables, BangPatterns #-}+{-# LANGUAGE BinaryLiterals, ScopedTypeVariables #-}  -- --  (c) The University of Glasgow 2002-2006@@ -15,7 +15,6 @@         readBinIface,         readBinIfaceHeader,         getSymtabName,-        getDictFastString,         CheckHiWay(..),         TraceBinIFace(..),         getWithUserData,@@ -24,11 +23,8 @@         -- * Internal serialisation functions         getSymbolTable,         putName,-        putDictionary,-        putFastString,         putSymbolTable,         BinSymbolTable(..),-        BinDictionary(..)     ) where  import GHC.Prelude@@ -48,7 +44,6 @@ import GHC.Types.Name.Cache import GHC.Types.SrcLoc import GHC.Platform-import GHC.Data.FastString import GHC.Settings.Constants import GHC.Utils.Fingerprint @@ -153,31 +148,28 @@ -- Names or FastStrings. getWithUserData :: Binary a => NameCache -> BinHandle -> IO a getWithUserData name_cache bh = do+  bh <- getTables name_cache bh+  get bh++-- | Setup a BinHandle to read something written using putWithTables+--+-- Reading names has the side effect of adding them into the given NameCache.+getTables :: NameCache -> BinHandle -> IO BinHandle+getTables name_cache bh = do     -- Read the dictionary     -- The next word in the file is a pointer to where the dictionary is     -- (probably at the end of the file)-    dict_p <- Binary.get bh-    data_p <- tellBin bh          -- Remember where we are now-    seekBin bh dict_p-    dict   <- getDictionary bh-    seekBin bh data_p             -- Back to where we were before+    dict <- Binary.forwardGet bh (getDictionary bh)      -- Initialise the user-data field of bh-    bh <- do-        bh <- return $ setUserData bh $ newReadState (error "getSymtabName")-                                                     (getDictFastString dict)-        symtab_p <- Binary.get bh     -- Get the symtab ptr-        data_p <- tellBin bh          -- Remember where we are now-        seekBin bh symtab_p-        symtab <- getSymbolTable bh name_cache-        seekBin bh data_p             -- Back to where we were before+    let bh_fs = setUserData bh $ newReadState (error "getSymtabName")+                                              (getDictFastString dict) -        -- It is only now that we know how to get a Name-        return $ setUserData bh $ newReadState (getSymtabName name_cache dict symtab)-                                               (getDictFastString dict)+    symtab <- Binary.forwardGet bh_fs (getSymbolTable bh_fs name_cache) -    -- Read the interface file-    get bh+    -- It is only now that we know how to get a Name+    return $ setUserData bh $ newReadState (getSymtabName name_cache dict symtab)+                                           (getDictFastString dict)  -- | Write an interface file writeBinIface :: Profile -> TraceBinIFace -> FilePath -> ModIface -> IO ()@@ -211,67 +203,66 @@ -- This segment should be read using `getWithUserData`. putWithUserData :: Binary a => TraceBinIFace -> BinHandle -> a -> IO () putWithUserData traceBinIface bh payload = do-    -- Remember where the dictionary pointer will go-    dict_p_p <- tellBin bh-    -- Placeholder for ptr to dictionary-    put_ bh dict_p_p+  (name_count, fs_count, _b) <- putWithTables bh (\bh' -> put bh' payload) -    -- Remember where the symbol table pointer will go-    symtab_p_p <- tellBin bh-    put_ bh symtab_p_p-    -- Make some initial state+  case traceBinIface of+    QuietBinIFace         -> return ()+    TraceBinIFace printer -> do+       printer (text "writeBinIface:" <+> int name_count+                                      <+> text "Names")+       printer (text "writeBinIface:" <+> int fs_count+                                      <+> text "dict entries")++-- | Write name/symbol tables+--+-- 1. setup the given BinHandle with Name/FastString table handling+-- 2. write the following+--    - FastString table pointer+--    - Name table pointer+--    - payload+--    - Name table+--    - FastString table+--+-- It returns (number of names, number of FastStrings, payload write result)+--+putWithTables :: BinHandle -> (BinHandle -> IO b) -> IO (Int,Int,b)+putWithTables bh put_payload = do+    -- initialize state for the name table and the FastString table.     symtab_next <- newFastMutInt 0     symtab_map <- newIORef emptyUFM-    let bin_symtab = BinSymbolTable {-                         bin_symtab_next = symtab_next,-                         bin_symtab_map  = symtab_map }-    dict_next_ref <- newFastMutInt 0-    dict_map_ref <- newIORef emptyUFM-    let bin_dict = BinDictionary {-                       bin_dict_next = dict_next_ref,-                       bin_dict_map  = dict_map_ref }+    let bin_symtab = BinSymbolTable+                      { bin_symtab_next = symtab_next+                      , bin_symtab_map  = symtab_map+                      } -    -- Put the main thing,-    bh <- return $ setUserData bh $ newWriteState (putName bin_dict bin_symtab)-                                                  (putName bin_dict bin_symtab)-                                                  (putFastString bin_dict)-    put_ bh payload+    (bh_fs, bin_dict, put_dict) <- initFSTable bh -    -- Write the symtab pointer at the front of the file-    symtab_p <- tellBin bh        -- This is where the symtab will start-    putAt bh symtab_p_p symtab_p  -- Fill in the placeholder-    seekBin bh symtab_p           -- Seek back to the end of the file+    (fs_count,(name_count,r)) <- forwardPut bh (const put_dict) $ do -    -- Write the symbol table itself-    symtab_next <- readFastMutInt symtab_next-    symtab_map  <- readIORef symtab_map-    putSymbolTable bh symtab_next symtab_map-    case traceBinIface of-      QuietBinIFace         -> return ()-      TraceBinIFace printer ->-         printer (text "writeBinIface:" <+> int symtab_next-                                        <+> text "Names")+      -- NB. write the dictionary after the symbol table, because+      -- writing the symbol table may create more dictionary entries.+      let put_symtab = do+            name_count <- readFastMutInt symtab_next+            symtab_map  <- readIORef symtab_map+            putSymbolTable bh_fs name_count symtab_map+            pure name_count -    -- NB. write the dictionary after the symbol table, because-    -- writing the symbol table may create more dictionary entries.+      forwardPut bh_fs (const put_symtab) $ do -    -- Write the dictionary pointer at the front of the file-    dict_p <- tellBin bh          -- This is where the dictionary will start-    putAt bh dict_p_p dict_p      -- Fill in the placeholder-    seekBin bh dict_p             -- Seek back to the end of the file+        -- BinHandle with FastString and Name writing support+        let ud_fs = getUserData bh_fs+        let ud_name = ud_fs+                        { ud_put_nonbinding_name = putName bin_dict bin_symtab+                        , ud_put_binding_name    = putName bin_dict bin_symtab+                        }+        let bh_name = setUserData bh ud_name -    -- Write the dictionary itself-    dict_next <- readFastMutInt dict_next_ref-    dict_map  <- readIORef dict_map_ref-    putDictionary bh dict_next dict_map-    case traceBinIface of-      QuietBinIFace         -> return ()-      TraceBinIFace printer ->-         printer (text "writeBinIface:" <+> int dict_next-                                        <+> text "dict entries")+        put_payload bh_name +    return (name_count, fs_count, r)  + -- | Initial ram buffer to allocate for writing interface files initBinMemSize :: Int initBinMemSize = 1024 * 1024@@ -287,9 +278,9 @@ --  putSymbolTable :: BinHandle -> Int -> UniqFM Name (Int,Name) -> IO ()-putSymbolTable bh next_off symtab = do-    put_ bh next_off-    let names = elems (array (0,next_off-1) (nonDetEltsUFM symtab))+putSymbolTable bh name_count symtab = do+    put_ bh name_count+    let names = elems (array (0,name_count-1) (nonDetEltsUFM symtab))       -- It's OK to use nonDetEltsUFM here because the elements have       -- indices that array uses to create order     mapM_ (\n -> serialiseName bh n symtab) names@@ -340,7 +331,7 @@   -- See Note [Symbol table representation of names]-putName :: BinDictionary -> BinSymbolTable -> BinHandle -> Name -> IO ()+putName :: FSTable -> BinSymbolTable -> BinHandle -> Name -> IO () putName _dict BinSymbolTable{                bin_symtab_map = symtab_map_ref,                bin_symtab_next = symtab_next }@@ -381,7 +372,7 @@         in           return $! case lookupKnownKeyName u of                       Nothing -> pprPanic "getSymtabName:unknown known-key unique"-                                          (ppr i $$ ppr u)+                                          (ppr i $$ ppr u $$ char tag $$ ppr ix)                       Just n  -> n        _ -> pprPanic "getSymtabName:unknown name tag" (ppr i)@@ -390,32 +381,5 @@         bin_symtab_next :: !FastMutInt, -- The next index to use         bin_symtab_map  :: !(IORef (UniqFM Name (Int,Name)))                                 -- indexed by Name-  }--putFastString :: BinDictionary -> BinHandle -> FastString -> IO ()-putFastString dict bh fs = allocateFastString dict fs >>= put_ bh--allocateFastString :: BinDictionary -> FastString -> IO Word32-allocateFastString BinDictionary { bin_dict_next = j_r,-                                   bin_dict_map  = out_r} f = do-    out <- readIORef out_r-    let !uniq = getUnique f-    case lookupUFM_Directly out uniq of-        Just (j, _)  -> return (fromIntegral j :: Word32)-        Nothing -> do-           j <- readFastMutInt j_r-           writeFastMutInt j_r (j + 1)-           writeIORef out_r $! addToUFM_Directly out uniq (j, f)-           return (fromIntegral j :: Word32)--getDictFastString :: Dictionary -> BinHandle -> IO FastString-getDictFastString dict bh = do-    j <- get bh-    return $! (dict ! fromIntegral (j :: Word32))--data BinDictionary = BinDictionary {-        bin_dict_next :: !FastMutInt, -- The next index to use-        bin_dict_map  :: !(IORef (UniqFM FastString (Int,FastString)))-                                -- indexed by FastString   } 
compiler/GHC/Iface/Errors.hs view
@@ -46,7 +46,7 @@   -- are the same   withPprStyle (mkUserStyle alwaysQualify AllTheWay) $     -- we want the Modules below to be qualified with package names,-    -- so reset the PrintUnqualified setting.+    -- so reset the NamePprCtx setting.     hsep [ text "Something is amiss; requested module "          , ppr requested_mod          , text "differs from name found in the interface file"
compiler/GHC/Iface/Ext/Binary.hs view
@@ -21,7 +21,6 @@ import GHC.Settings.Config        ( cProjectVersion ) import GHC.Prelude import GHC.Utils.Binary-import GHC.Iface.Binary           ( getDictFastString ) import GHC.Data.FastMutInt import GHC.Data.FastString        ( FastString ) import GHC.Types.Name
compiler/GHC/Iface/Ext/Types.hs view
@@ -143,7 +143,7 @@   = HTyVarTy Name   | HAppTy a (HieArgs a)   | HTyConApp IfaceTyCon (HieArgs a)-  | HForAllTy ((Name, a),ArgFlag) a+  | HForAllTy ((Name, a),ForAllTyFlag) a   | HFunTy a a a   | HQualTy a a           -- ^ type with constraint: @t1 => t2@ (see 'IfaceDFunTy')   | HLitTy IfaceTyLit@@ -206,7 +206,7 @@   -- | A list of type arguments along with their respective visibilities (ie. is--- this an argument that would return 'True' for 'isVisibleArgFlag'?).+-- this an argument that would return 'True' for 'isVisibleForAllTyFlag'?). newtype HieArgs a = HieArgs [(Bool,a)]   deriving (Functor, Foldable, Traversable, Eq) 
compiler/GHC/Iface/Ext/Utils.hs view
@@ -13,7 +13,6 @@ import GHC.Driver.Ppr import GHC.Data.FastString   ( FastString, mkFastString ) import GHC.Iface.Type-import GHC.Core.Multiplicity import GHC.Types.Name hiding (varName) import GHC.Types.Name.Set import GHC.Utils.Outputable hiding ( (<>) )@@ -22,6 +21,7 @@ import GHC.CoreToIface import GHC.Core.TyCon import GHC.Core.TyCo.Rep+import GHC.Core.TyCo.Compare( nonDetCmpType ) import GHC.Core.Type import GHC.Types.Var import GHC.Types.Var.Env@@ -41,6 +41,7 @@ import Data.Traversable           ( for ) import Data.Coerce import GHC.Utils.Monad.State.Strict hiding (get)+import GHC.Utils.Panic.Plain( assert ) import Control.Monad.Trans.Reader import qualified Data.Tree as Tree @@ -70,8 +71,8 @@       | Just ty' <- coreView ty       = go env ty' ts     go env (ForAllTy (Bndr tv vis) res) (t:ts)-      | isVisibleArgFlag vis = (True , t) : ts'-      | otherwise            = (False, t) : ts'+      | isVisibleForAllTyFlag vis = (True , t) : ts'+      | otherwise                 = (False, t) : ts'       where         ts' = go (extendTvSubst env tv t) res ts @@ -160,8 +161,8 @@     go (HLitTy l) = IfaceLitTy l     go (HForAllTy ((n,k),af) t) = let b = (occNameFS $ getOccName n, k)                                   in IfaceForAllTy (Bndr (IfaceTvBndr b) af) t-    go (HFunTy w a b)   = IfaceFunTy VisArg   w       a    b-    go (HQualTy pred b) = IfaceFunTy InvisArg many_ty pred b+    go (HFunTy w a b)   = IfaceFunTy visArgTypeLike   w       a    b+    go (HQualTy pred b) = IfaceFunTy invisArgTypeLike many_ty pred b     go (HCastTy a) = a     go HCoercionTy = IfaceTyVar "<coercion type>"     go (HTyConApp a xs) = IfaceTyConApp a (hieToIfaceArgs xs)@@ -240,9 +241,9 @@       ai <- getTypeIndex a       bi <- getTypeIndex b       wi <- getTypeIndex w-      return $ case af of-                 InvisArg -> case w of Many -> HQualTy ai bi; _ -> error "Unexpected non-unrestricted predicate"-                 VisArg   -> HFunTy wi ai bi+      return $ if isInvisibleFunArg af+               then assert (isManyTy w) $ HQualTy ai bi+               else                       HFunTy wi ai bi     go (LitTy a) = return $ HLitTy $ toIfaceTyLit a     go (CastTy t _) = do       i <- getTypeIndex t
compiler/GHC/Iface/Load.hs view
@@ -68,7 +68,6 @@ import GHC.Utils.Panic.Plain import GHC.Utils.Constants (debugIsOn) import GHC.Utils.Logger-import GHC.Utils.Trace  import GHC.Settings.Constants @@ -603,8 +602,11 @@ This is a mess.  -Note [HPT space leak] (#15111)-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Note [Home Unit Graph space leak]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Ticket: #15111+ In IfL, we defer some work until it is demanded using forkM, such as building TyThings from IfaceDecls. These thunks are stored in the ExternalPackageState, and they might never be poked.  If we're@@ -615,14 +617,15 @@ Therefore, when loading a package interface file , we use a "clean" version of the HscEnv with all the data about the currently loaded program stripped out. Most of the fields can be panics because-we'll never read them, but hsc_HPT needs to be empty because this+we'll never read them, but hsc_HUG needs to be empty because this interface will cause other interfaces to be loaded recursively, and-when looking up those interfaces we use the HPT in loadInterface.+when looking up those interfaces we use the HUG in loadInterface. We know that none of the interfaces below here can refer to-home-package modules however, so it's safe for the HPT to be empty.+home-package modules however, so it's safe for the HUG to be empty. -}  -- Note [GHC Heap Invariants]+-- Note [Home Unit Graph space leak] dontLeakTheHUG :: IfL a -> IfL a dontLeakTheHUG thing_inside = do   env <- getTopEnv@@ -1081,11 +1084,12 @@        qualifyImportedNames mod _            | mod == mi_module iface = NameUnqual            | otherwise              = NameNotInScope1-       print_unqual = QueryQualify qualifyImportedNames+       name_ppr_ctx = QueryQualify qualifyImportedNames                                    neverQualifyModules                                    neverQualifyPackages+                                   alwaysPrintPromTick    logMsg logger MCDump noSrcSpan-      $ withPprStyle (mkDumpStyle print_unqual)+      $ withPprStyle (mkDumpStyle name_ppr_ctx)       $ pprModIface unit_state iface  -- | Show a ModIface but don't display details; suitable for ModIfaces stored in
compiler/GHC/Iface/Make.hs view
@@ -47,7 +47,7 @@ import GHC.Core.InstEnv import GHC.Core.FamInstEnv import GHC.Core.Ppr-import GHC.Core.Unify( RoughMatchTc(..) )+import GHC.Core.RoughMap( RoughMatchTc(..) )  import GHC.Driver.Config.HsToCore.Usage import GHC.Driver.Env@@ -79,7 +79,6 @@ import GHC.Utils.Panic.Plain import GHC.Utils.Misc import GHC.Utils.Logger-import GHC.Utils.Trace  import GHC.Data.FastString import GHC.Data.Maybe@@ -551,7 +550,7 @@                   ifCType      = Nothing,                   ifRoles      = tyConRoles tycon,                   ifCtxt       = [],-                  ifCons       = IfDataTyCon [],+                  ifCons       = IfDataTyCon False [],                   ifGadtSyntax = False,                   ifParent     = IfNoParent })   where@@ -560,7 +559,7 @@     -- an error.     (tc_env1, tc_binders) = tidyTyConBinders env (tyConBinders tycon)     tc_tyvars      = binderVars tc_binders-    if_binders     = toIfaceTyCoVarBinders tc_binders+    if_binders     = toIfaceForAllBndrs tc_binders                      -- No tidying of the binders; they are already tidy     if_res_kind    = tidyToIfaceType tc_env1 (tyConResKind tycon)     if_syn_type ty = tidyToIfaceType tc_env1 ty@@ -585,9 +584,10 @@             axn  = coAxiomName ax      ifaceConDecls (NewTyCon { data_con = con })    = IfNewTyCon  (ifaceConDecl con)-    ifaceConDecls (DataTyCon { data_cons = cons }) = IfDataTyCon (map ifaceConDecl cons)-    ifaceConDecls (TupleTyCon { data_con = con })  = IfDataTyCon [ifaceConDecl con]-    ifaceConDecls (SumTyCon { data_cons = cons })  = IfDataTyCon (map ifaceConDecl cons)+    ifaceConDecls (DataTyCon { data_cons = cons, is_type_data = type_data })+      = IfDataTyCon type_data (map ifaceConDecl cons)+    ifaceConDecls (TupleTyCon { data_con = con })  = IfDataTyCon False [ifaceConDecl con]+    ifaceConDecls (SumTyCon { data_cons = cons })  = IfDataTyCon False (map ifaceConDecl cons)     ifaceConDecls AbstractTyCon                    = IfAbstractTyCon         -- The AbstractTyCon case happens when a TyCon has been trimmed         -- during tidying.@@ -601,7 +601,7 @@                     ifConInfix   = dataConIsInfix data_con,                     ifConWrapper = isJust (dataConWrapId_maybe data_con),                     ifConExTCvs  = map toIfaceBndr ex_tvs',-                    ifConUserTvBinders = map toIfaceForAllBndr user_bndrs',+                    ifConUserTvBinders = toIfaceForAllBndrs user_bndrs',                     ifConEqSpec  = map (to_eq_spec . eqSpecPair) eq_spec,                     ifConCtxt    = tidyToIfaceContext con_env2 theta,                     ifConArgTys  =@@ -628,18 +628,18 @@                      -- A bit grimy, perhaps, but it's simple!            (con_env2, ex_tvs') = tidyVarBndrs con_env1 ex_tvs-          user_bndrs' = map (tidyUserTyCoVarBinder con_env2) user_bndrs+          user_bndrs' = map (tidyUserForAllTyBinder con_env2) user_bndrs           to_eq_spec (tv,ty) = (tidyTyVar con_env2 tv, tidyToIfaceType con_env2 ty)            -- By this point, we have tidied every universal and existential-          -- tyvar. Because of the dcUserTyCoVarBinders invariant+          -- tyvar. Because of the dcUserForAllTyBinders invariant           -- (see Note [DataCon user type variable binders]), *every*           -- user-written tyvar must be contained in the substitution that           -- tidying produced. Therefore, tidying the user-written tyvars is a           -- simple matter of looking up each variable in the substitution,           -- which tidyTyCoVarOcc accomplishes.-          tidyUserTyCoVarBinder :: TidyEnv -> InvisTVBinder -> InvisTVBinder-          tidyUserTyCoVarBinder env (Bndr tv vis) =+          tidyUserForAllTyBinder :: TidyEnv -> InvisTVBinder -> InvisTVBinder+          tidyUserForAllTyBinder env (Bndr tv vis) =             Bndr (tidyTyCoVarOcc env tv) vis  classToIfaceDecl :: TidyEnv -> Class -> (TidyEnv, IfaceDecl)@@ -647,7 +647,7 @@   = ( env1     , IfaceClass { ifName   = getName tycon,                    ifRoles  = tyConRoles (classTyCon clas),-                   ifBinders = toIfaceTyCoVarBinders tc_binders,+                   ifBinders = toIfaceForAllBndrs tc_binders,                    ifBody   = body,                    ifFDs    = map toIfaceFD clas_fds })   where@@ -702,7 +702,7 @@ tidyTyConBinder env@(_, subst) tvb@(Bndr tv vis)  = case lookupVarEnv subst tv of      Just tv' -> (env,  Bndr tv' vis)-     Nothing  -> tidyTyCoVarBinder env tvb+     Nothing  -> tidyForAllTyBinder env tvb  tidyTyConBinders :: TidyEnv -> [TyConBinder] -> (TidyEnv, [TyConBinder]) tidyTyConBinders = mapAccumL tidyTyConBinder
compiler/GHC/Iface/Recomp.hs view
@@ -19,6 +19,7 @@ where  import GHC.Prelude+import GHC.Data.FastString  import GHC.Driver.Backend import GHC.Driver.Config.Finder@@ -50,7 +51,6 @@ import GHC.Utils.Exception import GHC.Utils.Logger import GHC.Utils.Constants (debugIsOn)-import GHC.Utils.Trace  import GHC.Types.Annotations import GHC.Types.Name@@ -169,7 +169,7 @@  data RecompReason   = UnitDepRemoved UnitId-  | ModulePackageChanged String+  | ModulePackageChanged FastString   | SourceFileChanged   | ThisUnitIdChanged   | ImpurePlugin@@ -201,7 +201,7 @@ instance Outputable RecompReason where   ppr = \case     UnitDepRemoved uid       -> ppr uid <+> text "removed"-    ModulePackageChanged s   -> text s <+> text "package changed"+    ModulePackageChanged s   -> ftext s <+> text "package changed"     SourceFileChanged        -> text "Source file changed"     ThisUnitIdChanged        -> text "-this-unit-id changed"     ImpurePlugin             -> text "Impure plugin forced recompilation"@@ -597,7 +597,7 @@                       -> [(t, GenLocated l ModuleName)]                     -> IfG                        [Either-                          CompileReason (Either (UnitId, ModuleName) (String, UnitId))]+                          CompileReason (Either (UnitId, ModuleName) (FastString, UnitId))]    classify_import find_import imports =     liftIO $ traverse (\(mb_pkg, L _ mod) ->            let reason = ModuleChanged mod@@ -613,9 +613,9 @@    prev_dep_mods = map (second gwib_mod) $ Set.toAscList $ dep_direct_mods (mi_deps iface)    prev_dep_pkgs = Set.toAscList (Set.union (dep_direct_pkgs (mi_deps iface))                                             (dep_plugin_pkgs (mi_deps iface)))-   bkpk_units    = map (("Signature",) . instUnitInstanceOf . moduleUnit) (requirementMerges units (moduleName (mi_module iface)))+   bkpk_units    = map ((fsLit "Signature",) . instUnitInstanceOf . moduleUnit) (requirementMerges units (moduleName (mi_module iface))) -   implicit_deps = map ("Implicit",) (implicitPackageDeps dflags)+   implicit_deps = map (fsLit "Implicit",) (implicitPackageDeps dflags)     -- GHC.Prim is very special and doesn't appear in ms_textual_imps but    -- ghc-prim will appear in the package dependencies still. In order to not confuse@@ -624,12 +624,12 @@                               Just home_unit                                 | homeUnitId home_unit == primUnitId                                 -> Left (primUnitId, mkModuleName "GHC.Prim")-                              _ -> Right ("GHC.Prim", primUnitId)+                              _ -> Right (fsLit "GHC.Prim", primUnitId)      classify _ (Found _ mod)     | (toUnitId $ moduleUnit mod) `elem` all_home_units = Right (Left ((toUnitId $ moduleUnit mod), moduleName mod))-    | otherwise = Right (Right (moduleNameString (moduleName mod), toUnitId $ moduleUnit mod))+    | otherwise = Right (Right (moduleNameFS (moduleName mod), toUnitId $ moduleUnit mod))    classify reason _ = Left (RecompBecause reason)     check_mods :: [(UnitId, ModuleName)] -> [(UnitId, ModuleName)] -> IO RecompileRequired@@ -650,7 +650,7 @@            text " not among previous dependencies"         return $ needsRecompileBecause $ ModuleAdded new -   check_packages :: [(String, UnitId)] -> [UnitId] -> IO RecompileRequired+   check_packages :: [(FastString, UnitId)] -> [UnitId] -> IO RecompileRequired    check_packages [] [] = return UpToDate    check_packages [] (old:_) = do      trace_hi_diffs logger $@@ -662,7 +662,7 @@     , new_unit == old = check_packages (dropWhile ((== new_unit) . snd) news) olds'     | otherwise = do         trace_hi_diffs logger $-         text "imported package" <+> text new_name <+> ppr new_unit <+>+         text "imported package" <+> ftext new_name <+> ppr new_unit <+>            text "not among previous dependencies"         return $ needsRecompileBecause $ ModulePackageChanged new_name @@ -1244,7 +1244,7 @@    iface_hash <- computeFingerprint putNameLiterally                       (mod_hash,                        mi_src_hash iface0,-                       ann_fn (mkVarOcc "module"),  -- See mkIfaceAnnCache+                       ann_fn (mkVarOccFS (fsLit "module")),  -- See mkIfaceAnnCache                        mi_usages iface0,                        sorted_deps,                        mi_hpc iface0)@@ -1639,7 +1639,7 @@     pair (IfaceAnnotation target value) =       (case target of           NamedTarget occn -> occn-          ModuleTarget _   -> mkVarOcc "module"+          ModuleTarget _   -> mkVarOccFS (fsLit "module")       , [value])     -- flipping (++), so the first argument is always short     env = mkOccEnv_C (flip (++)) (map pair anns)
compiler/GHC/Iface/Rename.hs view
@@ -1,7 +1,3 @@---{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}- -- | This module implements interface renaming, which is -- used to rewrite interface files on the fly when we -- are doing indefinite typechecking and need instantiations@@ -543,8 +539,8 @@ rnIfaceTyConParent IfNoParent = pure IfNoParent  rnIfaceConDecls :: Rename IfaceConDecls-rnIfaceConDecls (IfDataTyCon ds)-    = IfDataTyCon <$> mapM rnIfaceConDecl ds+rnIfaceConDecls (IfDataTyCon type_data ds)+    = IfDataTyCon type_data <$> mapM rnIfaceConDecl ds rnIfaceConDecls (IfNewTyCon d) = IfNewTyCon <$> rnIfaceConDecl d rnIfaceConDecls IfAbstractTyCon = pure IfAbstractTyCon @@ -632,7 +628,7 @@ rnIfaceExpr (IfaceCast expr co)     = IfaceCast <$> rnIfaceExpr expr <*> rnIfaceCo co rnIfaceExpr (IfaceLit lit)           = pure (IfaceLit lit)-rnIfaceExpr (IfaceLitRubbish rep)    = IfaceLitRubbish <$> rnIfaceType rep+rnIfaceExpr (IfaceLitRubbish tc rep) = IfaceLitRubbish tc <$> rnIfaceType rep rnIfaceExpr (IfaceFCall cc ty)       = IfaceFCall cc <$> rnIfaceType ty rnIfaceExpr (IfaceTick tickish expr) = IfaceTick tickish <$> rnIfaceExpr expr @@ -693,7 +689,7 @@     = IfaceTransCo <$> rnIfaceCo c1 <*> rnIfaceCo c2 rnIfaceCo (IfaceInstCo c1 c2)     = IfaceInstCo <$> rnIfaceCo c1 <*> rnIfaceCo c2-rnIfaceCo (IfaceNthCo d c) = IfaceNthCo d <$> rnIfaceCo c+rnIfaceCo (IfaceSelCo d c) = IfaceSelCo d <$> rnIfaceCo c rnIfaceCo (IfaceLRCo lr c) = IfaceLRCo lr <$> rnIfaceCo c rnIfaceCo (IfaceSubCo c) = IfaceSubCo <$> rnIfaceCo c rnIfaceCo (IfaceAxiomRuleCo ax cos)
compiler/GHC/Iface/Tidy.hs view
@@ -42,7 +42,6 @@ import GHC.Utils.Outputable import GHC.Utils.Misc( filterOut ) import GHC.Utils.Panic-import GHC.Utils.Trace import GHC.Utils.Logger as Logger import qualified GHC.Utils.Error as Err 
compiler/GHC/Iface/Tidy/StaticPtrTable.hs view
@@ -144,6 +144,7 @@ import GHC.Types.Id import GHC.Types.ForeignStubs import GHC.Data.Maybe+import GHC.Data.FastString  import Control.Monad.Trans.State.Strict import Data.List (intercalate)@@ -239,12 +240,17 @@ -- @fps@ is a list associating each binding corresponding to a static entry with -- its fingerprint. sptModuleInitCode :: Platform -> Module -> [SptEntry] -> CStub-sptModuleInitCode _        _        [] = mempty-sptModuleInitCode platform this_mod entries =+sptModuleInitCode platform this_mod entries+    -- no CStub if there is no entry+  | [] <- entries                           = mempty+    -- no CStub for the JS backend: it deals with it directly during JS code+    -- generation+  | ArchJavaScript <- platformArch platform = mempty+  | otherwise =     initializerCStub platform init_fn_nm empty init_fn_body `mappend`     finalizerCStub platform fini_fn_nm empty fini_fn_body   where-    init_fn_nm = mkInitializerStubLabel this_mod "spt"+    init_fn_nm = mkInitializerStubLabel this_mod (fsLit "spt")     init_fn_body = vcat         [  text "static StgWord64 k" <> int i <> text "[2] = "            <> pprFingerprint fp <> semi@@ -260,7 +266,7 @@         |  (i, SptEntry n fp) <- zip [0..] entries         ] -    fini_fn_nm = mkFinalizerStubLabel this_mod "spt"+    fini_fn_nm = mkFinalizerStubLabel this_mod (fsLit "spt")     fini_fn_body = vcat         [  text "StgWord64 k" <> int i <> text "[2] = "            <> pprFingerprint fp <> semi
compiler/GHC/IfaceToCore.hs view
@@ -57,7 +57,7 @@ import GHC.Core.InstEnv import GHC.Core.FamInstEnv import GHC.Core-import GHC.Core.Unify( RoughMatchTc(..) )+import GHC.Core.RoughMap( RoughMatchTc(..) ) import GHC.Core.Utils import GHC.Core.Unfold( calcUnfoldingGuidance ) import GHC.Core.Unfold.Make@@ -240,9 +240,9 @@     }  typecheckWholeCoreBindings :: IORef TypeEnv ->  WholeCoreBindings -> IfG [CoreBind]-typecheckWholeCoreBindings type_var (WholeCoreBindings prepd_binding this_mod _) =+typecheckWholeCoreBindings type_var (WholeCoreBindings tidy_bindings this_mod _) =   initIfaceLcl this_mod (text "typecheckWholeCoreBindings") NotBoot $ do-    tcTopIfaceBindings type_var prepd_binding+    tcTopIfaceBindings type_var tidy_bindings   {-@@ -338,7 +338,7 @@     mergeRoles roles1 roles2 = zipWithEqual "mergeRoles" max roles1 roles2  isRepInjectiveIfaceDecl :: IfaceDecl -> Bool-isRepInjectiveIfaceDecl IfaceData{ ifCons = IfDataTyCon _ } = True+isRepInjectiveIfaceDecl IfaceData{ ifCons = IfDataTyCon{} } = True isRepInjectiveIfaceDecl IfaceFamily{ ifFamFlav = IfaceDataFamilyTyCon } = True isRepInjectiveIfaceDecl _ = False @@ -1083,11 +1083,12 @@   = case if_cons of         IfAbstractTyCon           -> return AbstractTyCon-        IfDataTyCon cons+        IfDataTyCon type_data cons           -> do  { data_cons  <- mapM tc_con_decl cons                  ; return $                      mkLevPolyDataTyConRhs                        (isFixedRuntimeRepKind $ tyConResKind tycon)+                       type_data                        data_cons }         IfNewTyCon con           -> do  { data_con  <- tc_con_decl con@@ -1453,11 +1454,10 @@      go (IfaceReflCo t)           = Refl <$> tcIfaceType t     go (IfaceGReflCo r t mco)    = GRefl r <$> tcIfaceType t <*> go_mco mco-    go (IfaceFunCo r w c1 c2)    = mkFunCo r <$> go w <*> go c1 <*> go c2-    go (IfaceTyConAppCo r tc cs)-      = TyConAppCo r <$> tcIfaceTyCon tc <*> mapM go cs+    go (IfaceFunCo r w c1 c2)    = mkFunCoNoFTF r <$> go w <*> go c1 <*> go c2+    go (IfaceTyConAppCo r tc cs) = TyConAppCo r <$> tcIfaceTyCon tc <*> mapM go cs     go (IfaceAppCo c1 c2)        = AppCo <$> go c1 <*> go c2-    go (IfaceForAllCo tv k c)  = do { k' <- go k+    go (IfaceForAllCo tv k c)    = do { k' <- go k                                       ; bindIfaceBndr tv $ \ tv' ->                                         ForAllCo tv' k' <$> go c }     go (IfaceCoVarCo n)          = CoVarCo <$> go_var n@@ -1469,8 +1469,8 @@                                             <*> go c2     go (IfaceInstCo c1 t2)       = InstCo   <$> go c1                                             <*> go t2-    go (IfaceNthCo d c)          = do { c' <- go c-                                      ; return $ mkNthCo (nthCoRole d c') d c' }+    go (IfaceSelCo d c)          = do { c' <- go c+                                      ; return $ mkSelCo d c' }     go (IfaceLRCo lr c)          = LRCo lr  <$> go c     go (IfaceKindCo c)           = KindCo   <$> go c     go (IfaceSubCo c)            = SubCo    <$> go c@@ -1512,9 +1512,9 @@ tcIfaceExpr (IfaceExt gbl)   = Var <$> tcIfaceExtId gbl -tcIfaceExpr (IfaceLitRubbish rep)+tcIfaceExpr (IfaceLitRubbish tc rep)   = do rep' <- tcIfaceType rep-       return (Lit (LitRubbish rep'))+       return (Lit (LitRubbish tc rep'))  tcIfaceExpr (IfaceLit lit)   = do lit' <- tcIfaceLit lit@@ -1559,7 +1559,7 @@     case_bndr_name <- newIfaceName (mkVarOccFS case_bndr)     let         scrut_ty   = exprType scrut'-        case_mult = Many+        case_mult  = ManyTy         case_bndr' = mkLocalIdOrCoVar case_bndr_name case_mult scrut_ty      -- "OrCoVar" since a coercion can be a scrutinee with -fdefer-type-errors      -- (e.g. see test T15695). Ticket #17291 covers fixing this problem.@@ -1579,7 +1579,7 @@         ; ty'     <- tcIfaceType ty         ; id_info <- tcIdInfo False {- Don't ignore prags; we are inside one! -}                               NotTopLevel name ty' info-        ; let id = mkLocalIdWithInfo name Many ty' id_info+        ; let id = mkLocalIdWithInfo name ManyTy ty' id_info                      `asJoinId_maybe` tcJoinInfo ji         ; rhs' <- tcIfaceExpr rhs         ; body' <- extendIfaceIdEnv [id] (tcIfaceExpr body)@@ -1595,7 +1595,7 @@    tc_rec_bndr (IfLetBndr fs ty _ ji)      = do { name <- newIfaceName (mkVarOccFS fs)           ; ty'  <- tcIfaceType ty-          ; return (mkLocalId name Many ty' `asJoinId_maybe` tcJoinInfo ji) }+          ; return (mkLocalId name ManyTy ty' `asJoinId_maybe` tcJoinInfo ji) }    tc_pair (IfLetBndr _ _ info _, rhs) id      = do { rhs' <- tcIfaceExpr rhs           ; id_info <- tcIdInfo False {- Don't ignore prags; we are inside one! -}@@ -1957,11 +1957,12 @@ -- this expression *after* typechecking T.  tcIfaceTyCon :: IfaceTyCon -> IfL TyCon-tcIfaceTyCon (IfaceTyCon name info)+tcIfaceTyCon (IfaceTyCon name _info)   = do { thing <- tcIfaceGlobal name-       ; return $ case ifaceTyConIsPromoted info of-           NotPromoted -> tyThingTyCon thing-           IsPromoted  -> promoteDataCon $ tyThingDataCon thing }+       ; case thing of+              ATyCon tc -> return tc+              AConLike (RealDataCon dc) -> return (promoteDataCon dc)+              _ -> pprPanic "tcIfaceTyCon" (ppr thing) }  tcIfaceCoAxiom :: Name -> IfL (CoAxiom Branched) tcIfaceCoAxiom name = do { thing <- tcIfaceImplicit name
+ compiler/GHC/JS/Make.hs view
@@ -0,0 +1,715 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE GADTs #-}++{-# OPTIONS_GHC -fno-warn-orphans #-} -- only for Num, Fractional on JExpr++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.JS.Make+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+--+-- * Domain and Purpose+--+--     GHC.JS.Make defines helper functions to ease the creation of JavaScript+--     ASTs as defined in 'GHC.JS.Syntax'. Its purpose is twofold: make the EDSL+--     more ergonomic to program in, and make errors in the EDSL /look/ obvious+--     because the EDSL is untyped. It is primarily concerned with injecting+--     terms into the domain of the EDSL to construct JS programs in Haskell.+--+-- * Strategy+--+--     The strategy for this module comes straight from gentzen; where we have+--     two types of helper functions. Functions which inject terms into the+--     EDSL, and combinator functions which operate on terms in the EDSL to+--     construct new terms in the EDSL. Crucially, missing from this module are+--     corresponding /elimination/ or /destructing/ functions which would+--     project information from the EDSL back to Haskell. See+--     'GHC.StgToJS.UnitUtils' and 'GHC.StgToJS.CoreUtils' for such functions.+--+--      * /Introduction/ functions+--+--           We define various primitive helpers which /introduce/ terms in the+--           EDSL, for example 'jVar', 'jLam', and 'var' and 'jString'. Notice+--           that the type of each of these functions have the domain @isSat a+--           => a -> ...@; indicating that they each take something that /can/+--           be injected into the EDSL domain, and the range 'JExpr' or 'JStat';+--           indicating the corresponding value in the EDSL domain. Similarly+--           this module exports two typeclasses 'ToExpr' and 'ToSat', 'ToExpr'+--           injects values as a JS expression into the EDSL. 'ToSat' ensures+--           that terms introduced into the EDSL carry identifier information so+--           terms in the EDSL must have meaning.+--+--      * /Combinator/ functions+--+--           The rest of the module defines combinators which create terms in+--           the EDSL from terms in the EDSL. Notable examples are '|=' and+--           '||=', '|=' is sugar for 'AssignStat', it is a binding form that+--           declares @foo = bar@ /assuming/ foo has been already declared.+--           '||=' is more sugar on top of '|=', it is also a binding form that+--           declares the LHS of '|=' before calling '|=' to bind a value, bar,+--           to a variable foo. Other common examples are the 'if_' and 'math_'+--           helpers such as 'math_cos'.+--+-- * Consumers+--+--     The entire JS backend consumes this module, e.g., the modules in+--     GHC.StgToJS.\*.+--+-- * Notation+--+--     In this module we use @==>@ in docstrings to show the translation from+--     the JS EDSL domain to JS code. For example, @foo ||= bar ==> var foo; foo+--     = bar;@ should be read as @foo ||= bar@ is in the EDSL domain and results+--     in the JS code @var foo; foo = bar;@ when compiled.+-----------------------------------------------------------------------------+module GHC.JS.Make+  ( -- * Injection Type classes+    -- $classes+    ToJExpr(..)+  , ToStat(..)+  -- * Introduction functions+  -- $intro_funcs+  , var+  , jString+  , jLam, jVar, jFor, jForIn, jForEachIn, jTryCatchFinally+  -- * Combinators+  -- $combinators+  , (||=), (|=), (.==.), (.===.), (.!=.), (.!==.), (.!)+  , (.>.), (.>=.), (.<.), (.<=.)+  , (.<<.), (.>>.), (.>>>.)+  , (.|.), (.||.), (.&&.)+  , if_, if10, if01, ifS, ifBlockS+  , jwhenS+  , app, appS, returnS+  , loop, loopBlockS+  , preIncrS, postIncrS+  , preDecrS, postDecrS+  , off8, off16, off32, off64+  , mask8, mask16+  , signExtend8, signExtend16+  , typeof+  , returnStack, assignAllEqual, assignAll, assignAllReverseOrder+  , declAssignAll+  , nullStat, (.^)+  , trace+  -- ** Hash combinators+  , jhEmpty+  , jhSingle+  , jhAdd+  , jhFromList+  -- * Literals+  -- $literals+  , null_+  , undefined_+  , false_+  , true_+  , zero_+  , one_+  , two_+  , three_+  -- ** Math functions+  -- $math+  , math_log, math_sin, math_cos, math_tan, math_exp, math_acos, math_asin,+    math_atan, math_abs, math_pow, math_sqrt, math_asinh, math_acosh, math_atanh,+    math_cosh, math_sinh, math_tanh, math_expm1, math_log1p, math_fround+  -- * Statement helpers+  , decl+  -- * Miscellaneous+  -- $misc+  , allocData, allocClsA+  , dataFieldName, dataFieldNames+  )+where++import GHC.Prelude hiding ((.|.))++import GHC.JS.Syntax++import Control.Arrow ((***))++import Data.Array+import qualified Data.Map as M+import qualified Data.List as List++import GHC.Utils.Outputable (Outputable (..))+import GHC.Data.FastString+import GHC.Utils.Monad.State.Strict+import GHC.Utils.Panic+import GHC.Utils.Misc+import GHC.Types.Unique.Map++--------------------------------------------------------------------------------+--                        Type Classes+--------------------------------------------------------------------------------+-- $classes+-- The 'ToJExpr' class handles injection of of things into the EDSL as a JS+-- expression++-- | Things that can be marshalled into javascript values.+-- Instantiate for any necessary data structures.+class ToJExpr a where+    toJExpr         :: a   -> JExpr+    toJExprFromList :: [a] -> JExpr+    toJExprFromList = ValExpr . JList . map toJExpr++instance ToJExpr a => ToJExpr [a] where+    toJExpr = toJExprFromList++instance ToJExpr JExpr where+    toJExpr = id++instance ToJExpr () where+    toJExpr _ = ValExpr $ JList []++instance ToJExpr Bool where+    toJExpr True  = var "true"+    toJExpr False = var "false"++instance ToJExpr JVal where+    toJExpr = ValExpr++instance ToJExpr a => ToJExpr (UniqMap FastString a) where+    toJExpr = ValExpr . JHash . mapUniqMap toJExpr++instance ToJExpr a => ToJExpr (M.Map String a) where+    toJExpr = ValExpr . JHash . listToUniqMap . map (mkFastString *** toJExpr) . M.toList++instance ToJExpr Double where+    toJExpr = ValExpr . JDouble . SaneDouble++instance ToJExpr Int where+    toJExpr = ValExpr . JInt . fromIntegral++instance ToJExpr Integer where+    toJExpr = ValExpr . JInt++instance ToJExpr Char where+    toJExpr = ValExpr . JStr . mkFastString . (:[])+    toJExprFromList = ValExpr . JStr . mkFastString+--        where escQuotes = tailDef "" . initDef "" . show++instance ToJExpr Ident where+    toJExpr = ValExpr . JVar++instance ToJExpr FastString where+    toJExpr = ValExpr . JStr++instance (ToJExpr a, ToJExpr b) => ToJExpr (a,b) where+    toJExpr (a,b) = ValExpr . JList $ [toJExpr a, toJExpr b]++instance (ToJExpr a, ToJExpr b, ToJExpr c) => ToJExpr (a,b,c) where+    toJExpr (a,b,c) = ValExpr . JList $ [toJExpr a, toJExpr b, toJExpr c]++instance (ToJExpr a, ToJExpr b, ToJExpr c, ToJExpr d) => ToJExpr (a,b,c,d) where+    toJExpr (a,b,c,d) = ValExpr . JList $ [toJExpr a, toJExpr b, toJExpr c, toJExpr d]+instance (ToJExpr a, ToJExpr b, ToJExpr c, ToJExpr d, ToJExpr e) => ToJExpr (a,b,c,d,e) where+    toJExpr (a,b,c,d,e) = ValExpr . JList $ [toJExpr a, toJExpr b, toJExpr c, toJExpr d, toJExpr e]+instance (ToJExpr a, ToJExpr b, ToJExpr c, ToJExpr d, ToJExpr e, ToJExpr f) => ToJExpr (a,b,c,d,e,f) where+    toJExpr (a,b,c,d,e,f) = ValExpr . JList $ [toJExpr a, toJExpr b, toJExpr c, toJExpr d, toJExpr e, toJExpr f]+++-- | The 'ToStat' class handles injection of of things into the EDSL as a JS+-- statement. This ends up being polymorphic sugar for JS blocks, see helper+-- function 'GHC.JS.Make.expr2stat'. Instantiate for any necessary data+-- structures.+class ToStat a where+    toStat :: a -> JStat++instance ToStat JStat where+    toStat = id++instance ToStat [JStat] where+    toStat = BlockStat++instance ToStat JExpr where+    toStat = expr2stat++instance ToStat [JExpr] where+    toStat = BlockStat . map expr2stat++--------------------------------------------------------------------------------+--                        Introduction Functions+--------------------------------------------------------------------------------+-- $intro_functions+-- Introduction functions are functions that map values or terms in the Haskell+-- domain to the JS EDSL domain++-- | Create a new anonymous function. The result is a 'GHC.JS.Syntax.JExpr'+-- expression.+-- Usage:+--+-- > jLam $ \x -> jVar x + one_+-- > jLam $ \f -> (jLam $ \x -> (f `app` (x `app` x))) `app` (jLam $ \x -> (f `app` (x `app` x)))+jLam :: ToSat a => a -> JExpr+jLam f = ValExpr . UnsatVal . IS $ do+           (block,is) <- runIdentSupply $ toSat_ f []+           return $ JFunc is block++-- | Introduce a new variable into scope for the duration+-- of the enclosed expression. The result is a block statement.+-- Usage:+--+-- @jVar $ \x y -> mconcat [jVar x ||= one_, jVar y ||= two_, jVar x + jVar y]@+jVar :: ToSat a => a -> JStat+jVar f = UnsatBlock . IS $ do+           (block, is) <- runIdentSupply $ toSat_ f []+           let addDecls (BlockStat ss) =+                  BlockStat $ map decl is ++ ss+               addDecls x = x+           return $ addDecls block++-- | Create a 'for in' statement.+-- Usage:+--+-- @jForIn {expression} $ \x -> {block involving x}@+jForIn :: ToSat a => JExpr -> (JExpr -> a)  -> JStat+jForIn e f = UnsatBlock . IS $ do+               (block, is) <- runIdentSupply $ toSat_ f []+               let i = List.head is+               return $ decl i `mappend` ForInStat False i e block++-- | As with "jForIn" but creating a \"for each in\" statement.+jForEachIn :: ToSat a => JExpr -> (JExpr -> a) -> JStat+jForEachIn e f = UnsatBlock . IS $ do+               (block, is) <- runIdentSupply $ toSat_ f []+               let i = List.head is+               return $ decl i `mappend` ForInStat True i e block++-- | As with "jForIn" but creating a \"for each in\" statement.+jTryCatchFinally :: (ToSat a) => JStat -> a -> JStat -> JStat+jTryCatchFinally s f s2 = UnsatBlock . IS $ do+                     (block, is) <- runIdentSupply $ toSat_ f []+                     let i = List.head is+                     return $ TryStat s i block s2++-- | construct a JS variable reference+var :: FastString -> JExpr+var = ValExpr . JVar . TxtI++-- | Convert a ShortText to a Javascript String+jString :: FastString -> JExpr+jString = toJExpr++-- | Create a 'for' statement+jFor :: (ToJExpr a, ToStat b) => JStat -> a -> JStat -> b -> JStat+jFor before p after b = BlockStat [before, WhileStat False (toJExpr p) b']+    where b' = case toStat b of+                 BlockStat xs -> BlockStat $ xs ++ [after]+                 x -> BlockStat [x,after]++-- | construct a js declaration with the given identifier+decl :: Ident -> JStat+decl i = DeclStat i Nothing++-- | The empty JS HashMap+jhEmpty :: M.Map k JExpr+jhEmpty = M.empty++-- | A singleton JS HashMap+jhSingle :: (Ord k, ToJExpr a) => k -> a -> M.Map k JExpr+jhSingle k v = jhAdd k v jhEmpty++-- | insert a key-value pair into a JS HashMap+jhAdd :: (Ord k, ToJExpr a) => k -> a -> M.Map k JExpr -> M.Map k JExpr+jhAdd  k v m = M.insert k (toJExpr v) m++-- | Construct a JS HashMap from a list of key-value pairs+jhFromList :: [(FastString, JExpr)] -> JVal+jhFromList = JHash . listToUniqMap++-- | The empty JS statement+nullStat :: JStat+nullStat = BlockStat []+++--------------------------------------------------------------------------------+--                             Combinators+--------------------------------------------------------------------------------+-- $combinators+-- Combinators operate on terms in the JS EDSL domain to create new terms in the+-- EDSL domain.++-- | JS infix Equality operators+(.==.), (.===.), (.!=.), (.!==.) :: JExpr -> JExpr -> JExpr+(.==.)  = InfixExpr EqOp+(.===.) = InfixExpr StrictEqOp+(.!=.)  = InfixExpr NeqOp+(.!==.) = InfixExpr StrictNeqOp++infixl 6 .==., .===., .!=., .!==.++-- | JS infix Ord operators+(.>.), (.>=.), (.<.), (.<=.) :: JExpr -> JExpr -> JExpr+(.>.)  = InfixExpr GtOp+(.>=.) = InfixExpr GeOp+(.<.)  = InfixExpr LtOp+(.<=.) = InfixExpr LeOp++infixl 7 .>., .>=., .<., .<=.++-- | JS infix bit operators+(.|.), (.||.), (.&&.)  :: JExpr -> JExpr -> JExpr+(.|.)   = InfixExpr BOrOp+(.||.)  = InfixExpr LOrOp+(.&&.)  = InfixExpr LAndOp++infixl 8 .||., .&&.++-- | JS infix bit shift operators+(.<<.), (.>>.), (.>>>.) :: JExpr -> JExpr -> JExpr+(.<<.)  = InfixExpr LeftShiftOp+(.>>.)  = InfixExpr RightShiftOp+(.>>>.) = InfixExpr ZRightShiftOp++infixl 9 .<<., .>>., .>>>.++-- | Given a 'JExpr', return the its type.+typeof :: JExpr -> JExpr+typeof = UOpExpr TypeofOp++-- | JS if-expression+--+-- > if_ e1 e2 e3 ==> e1 ? e2 : e3+if_ :: JExpr -> JExpr -> JExpr -> JExpr+if_ e1 e2 e3 = IfExpr e1 e2 e3++-- | If-expression which returns statements, see related 'ifBlockS'+--+-- > if e s1 s2 ==> if(e) { s1 } else { s2 }+ifS :: JExpr -> JStat -> JStat -> JStat+ifS e s1 s2 = IfStat e s1 s2++-- | A when-statement as syntactic sugar via `ifS`+--+-- > jwhenS cond block ==> if(cond) { block } else {  }+jwhenS :: JExpr -> JStat -> JStat+jwhenS cond block = ifS cond block mempty++-- | If-expression which returns blocks+--+-- > ifBlockS e s1 s2 ==> if(e) { s1 } else { s2 }+ifBlockS :: JExpr -> [JStat] -> [JStat] -> JStat+ifBlockS e s1 s2 = IfStat e (mconcat s1) (mconcat s2)++-- | if-expression that returns 1 if condition <=> true, 0 otherwise+--+-- > if10 e ==> e ? 1 : 0+if10 :: JExpr -> JExpr+if10 e = IfExpr e one_ zero_++-- | if-expression that returns 0 if condition <=> true, 1 otherwise+--+-- > if01 e ==> e ? 0 : 1+if01 :: JExpr -> JExpr+if01 e = IfExpr e zero_ one_++-- | an expression application, see related 'appS'+--+-- > app f xs ==> f(xs)+app :: FastString -> [JExpr] -> JExpr+app f xs = ApplExpr (var f) xs++-- | A statement application, see the expression form 'app'+appS :: FastString -> [JExpr] -> JStat+appS f xs = ApplStat (var f) xs++-- | Return a 'JExpr'+returnS :: JExpr -> JStat+returnS e = ReturnStat e++-- | "for" loop with increment at end of body+loop :: JExpr -> (JExpr -> JExpr) -> (JExpr -> JStat) -> JStat+loop initial test body = jVar $ \i ->+  mconcat [ i |= initial+          , WhileStat False (test i) (body i)+          ]++-- | "for" loop with increment at end of body+loopBlockS :: JExpr -> (JExpr -> JExpr) -> (JExpr -> [JStat]) -> JStat+loopBlockS initial test body = jVar $ \i ->+  mconcat [ i |= initial+          , WhileStat False (test i) (mconcat (body i))+          ]++-- | Prefix-increment a 'JExpr'+preIncrS :: JExpr -> JStat+preIncrS x = UOpStat PreIncOp x++-- | Postfix-increment a 'JExpr'+postIncrS :: JExpr -> JStat+postIncrS x = UOpStat PostIncOp x++-- | Prefix-decrement a 'JExpr'+preDecrS :: JExpr -> JStat+preDecrS x = UOpStat PreDecOp x++-- | Postfix-decrement a 'JExpr'+postDecrS :: JExpr -> JStat+postDecrS x = UOpStat PostDecOp x++-- | Byte indexing of o with a 64-bit offset+off64 :: JExpr -> JExpr -> JExpr+off64 o i = Add o (i .<<. three_)++-- | Byte indexing of o with a 32-bit offset+off32 :: JExpr -> JExpr -> JExpr+off32 o i = Add o (i .<<. two_)++-- | Byte indexing of o with a 16-bit offset+off16 :: JExpr -> JExpr -> JExpr+off16 o i = Add o (i .<<. one_)++-- | Byte indexing of o with a 8-bit offset+off8 :: JExpr -> JExpr -> JExpr+off8 o i = Add o i++-- | a bit mask to retrieve the lower 8-bits+mask8 :: JExpr -> JExpr+mask8 x = BAnd x (Int 0xFF)++-- | a bit mask to retrieve the lower 16-bits+mask16 :: JExpr -> JExpr+mask16 x = BAnd x (Int 0xFFFF)++-- | Sign-extend/narrow a 8-bit value+signExtend8 :: JExpr -> JExpr+signExtend8 x = (BAnd x (Int 0x7F  )) `Sub` (BAnd x (Int 0x80))++-- | Sign-extend/narrow a 16-bit value+signExtend16 :: JExpr -> JExpr+signExtend16 x = (BAnd x (Int 0x7FFF)) `Sub` (BAnd x (Int 0x8000))++-- | Select a property 'prop', from and object 'obj'+--+-- > obj .^ prop ==> obj.prop+(.^) :: JExpr -> FastString -> JExpr+obj .^ prop = SelExpr obj (TxtI prop)+infixl 8 .^++-- | Assign a variable to an expression+--+-- > foo |= expr ==> var foo = expr;+(|=) :: JExpr -> JExpr -> JStat+(|=) = AssignStat++-- | Declare a variable and then Assign the variable to an expression+--+-- > foo |= expr ==> var foo; foo = expr;+(||=) :: Ident -> JExpr -> JStat+i ||= ex = DeclStat i (Just ex)++infixl 2 ||=, |=++-- | return the expression at idx of obj+--+-- > obj .! idx ==> obj[idx]+(.!) :: JExpr -> JExpr -> JExpr+(.!) = IdxExpr++infixl 8 .!++assignAllEqual :: HasDebugCallStack => [JExpr] -> [JExpr] -> JStat+assignAllEqual xs ys = mconcat (zipWithEqual "assignAllEqual" (|=) xs ys)++assignAll :: [JExpr] -> [JExpr] -> JStat+assignAll xs ys = mconcat (zipWith (|=) xs ys)++assignAllReverseOrder :: [JExpr] -> [JExpr] -> JStat+assignAllReverseOrder xs ys = mconcat (reverse (zipWith (|=) xs ys))++declAssignAll :: [Ident] -> [JExpr] -> JStat+declAssignAll xs ys = mconcat (zipWith (||=) xs ys)++trace :: ToJExpr a => a -> JStat+trace ex = appS "h$log" [toJExpr ex]+++--------------------------------------------------------------------------------+--                             Literals+--------------------------------------------------------------------------------+-- $literals+-- Literals in the JS EDSL are constants in the Haskell domain. These are useful+-- helper values and never change++-- | The JS literal 'null'+null_ :: JExpr+null_ = var "null"++-- | The JS literal 0+zero_ :: JExpr+zero_ = Int 0++-- | The JS literal 1+one_ :: JExpr+one_ = Int 1++-- | The JS literal 2+two_ :: JExpr+two_ = Int 2++-- | The JS literal 3+three_ :: JExpr+three_ = Int 3++-- | The JS literal 'undefined'+undefined_ :: JExpr+undefined_ = var "undefined"++-- | The JS literal 'true'+true_ :: JExpr+true_ = var "true"++-- | The JS literal 'false'+false_ :: JExpr+false_ = var "false"++returnStack :: JStat+returnStack = ReturnStat (ApplExpr (var "h$rs") [])+++--------------------------------------------------------------------------------+--                             Math functions+--------------------------------------------------------------------------------+-- $math+-- Math functions in the EDSL are literals, with the exception of 'math_' which+-- is the sole math introduction function.++math :: JExpr+math = var "Math"++math_ :: FastString -> [JExpr] -> JExpr+math_ op args = ApplExpr (math .^ op) args++math_log, math_sin, math_cos, math_tan, math_exp, math_acos, math_asin, math_atan,+  math_abs, math_pow, math_sqrt, math_asinh, math_acosh, math_atanh, math_sign,+  math_sinh, math_cosh, math_tanh, math_expm1, math_log1p, math_fround+  :: [JExpr] -> JExpr+math_log   = math_ "log"+math_sin   = math_ "sin"+math_cos   = math_ "cos"+math_tan   = math_ "tan"+math_exp   = math_ "exp"+math_acos  = math_ "acos"+math_asin  = math_ "asin"+math_atan  = math_ "atan"+math_abs   = math_ "abs"+math_pow   = math_ "pow"+math_sign  = math_ "sign"+math_sqrt  = math_ "sqrt"+math_asinh = math_ "asinh"+math_acosh = math_ "acosh"+math_atanh = math_ "atanh"+math_sinh  = math_ "sinh"+math_cosh  = math_ "cosh"+math_tanh  = math_ "tanh"+math_expm1 = math_ "expm1"+math_log1p = math_ "log1p"+math_fround = math_ "fround"++instance Num JExpr where+    x + y = InfixExpr AddOp x y+    x - y = InfixExpr SubOp x y+    x * y = InfixExpr MulOp x y+    abs x    = math_abs [x]+    negate x = UOpExpr NegOp x+    signum x = math_sign [x]+    fromInteger x = ValExpr (JInt x)++instance Fractional JExpr where+    x / y = InfixExpr DivOp x y+    fromRational x = ValExpr (JDouble (realToFrac x))+++--------------------------------------------------------------------------------+--                             Miscellaneous+--------------------------------------------------------------------------------+-- $misc+-- Everything else,++-- | Cache "dXXX" field names+dataFieldCache :: Array Int FastString+dataFieldCache = listArray (0,nFieldCache) (map (mkFastString . ('d':) . show) [(0::Int)..nFieldCache])++nFieldCache :: Int+nFieldCache  = 16384++dataFieldName :: Int -> FastString+dataFieldName i+  | i < 1 || i > nFieldCache = panic "dataFieldName" (ppr i)+  | otherwise                = dataFieldCache ! i++dataFieldNames :: [FastString]+dataFieldNames = fmap dataFieldName [1..nFieldCache]+++-- | Cache "h$dXXX" names+dataCache :: Array Int FastString+dataCache = listArray (0,1024) (map (mkFastString . ("h$d"++) . show) [(0::Int)..1024])++allocData :: Int -> JExpr+allocData i = toJExpr (TxtI (dataCache ! i))++-- | Cache "h$cXXX" names+clsCache :: Array Int FastString+clsCache = listArray (0,1024) (map (mkFastString . ("h$c"++) . show) [(0::Int)..1024])++allocClsA :: Int -> JExpr+allocClsA i = toJExpr (TxtI (clsCache ! i))+++--------------------------------------------------------------------------------+-- New Identifiers+--------------------------------------------------------------------------------++-- | The 'ToSat' class is heavily used in the Introduction function. It ensures+-- that all identifiers in the EDSL are tracked and named with an 'IdentSupply'.+class ToSat a where+    toSat_ :: a -> [Ident] -> IdentSupply (JStat, [Ident])++instance ToSat [JStat] where+    toSat_ f vs = IS $ return $ (BlockStat f, reverse vs)++instance ToSat JStat where+    toSat_ f vs = IS $ return $ (f, reverse vs)++instance ToSat JExpr where+    toSat_ f vs = IS $ return $ (toStat f, reverse vs)++instance ToSat [JExpr] where+    toSat_ f vs = IS $ return $ (BlockStat $ map expr2stat f, reverse vs)++instance (ToSat a, b ~ JExpr) => ToSat (b -> a) where+    toSat_ f vs = IS $ do+      x <- takeOneIdent+      runIdentSupply $ toSat_ (f (ValExpr $ JVar x)) (x:vs)++-- | Convert A JS expression to a JS statement where applicable. This only+-- affects applications; 'ApplExpr', If-expressions; 'IfExpr', and Unary+-- expression; 'UOpExpr'.+expr2stat :: JExpr -> JStat+expr2stat (ApplExpr x y) = (ApplStat x y)+expr2stat (IfExpr x y z) = IfStat x (expr2stat y) (expr2stat z)+expr2stat (UOpExpr o x) = UOpStat o x+expr2stat _ = nullStat++takeOneIdent :: State [Ident] Ident+takeOneIdent = do+  xxs <- get+  case xxs of+    (x:xs) -> do+      put xs+      return x+    _ -> error "takeOneIdent: empty list"+
+ compiler/GHC/JS/Ppr.hs view
@@ -0,0 +1,294 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE BlockArguments #-}++-- For Outputable instances for JS syntax+{-# OPTIONS_GHC -Wno-orphans #-}++-- | Pretty-printing JavaScript+module GHC.JS.Ppr+  ( renderJs+  , renderJs'+  , renderPrefixJs+  , renderPrefixJs'+  , JsToDoc(..)+  , defaultRenderJs+  , RenderJs(..)+  , jsToDoc+  , pprStringLit+  , flattenBlocks+  , braceNest+  , hangBrace+  )+where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Transform+++import Data.Char (isControl, ord)+import Data.List (sortOn)++import Numeric(showHex)++import GHC.Utils.Outputable (Outputable (..), docToSDoc)+import GHC.Utils.Ppr as PP+import GHC.Data.FastString+import GHC.Types.Unique.Map++instance Outputable JExpr where+  ppr = docToSDoc . renderJs++instance Outputable JVal where+  ppr = docToSDoc . renderJs+++($$$) :: Doc -> Doc -> Doc+x $$$ y = nest 2 $ x $+$ y++-- | Render a syntax tree as a pretty-printable document+-- (simply showing the resultant doc produces a nice,+-- well formatted String).+renderJs :: (JsToDoc a, JMacro a) => a -> Doc+renderJs = renderJs' defaultRenderJs++renderJs' :: (JsToDoc a, JMacro a) => RenderJs -> a -> Doc+renderJs' r = jsToDocR r . jsSaturate Nothing++data RenderJs = RenderJs+  { renderJsS :: !(RenderJs -> JStat -> Doc)+  , renderJsE :: !(RenderJs -> JExpr -> Doc)+  , renderJsV :: !(RenderJs -> JVal  -> Doc)+  , renderJsI :: !(RenderJs -> Ident -> Doc)+  }++defaultRenderJs :: RenderJs+defaultRenderJs = RenderJs defRenderJsS defRenderJsE defRenderJsV defRenderJsI++jsToDoc :: JsToDoc a => a -> Doc+jsToDoc = jsToDocR defaultRenderJs++-- | Render a syntax tree as a pretty-printable document, using a given prefix+-- to all generated names. Use this with distinct prefixes to ensure distinct+-- generated names between independent calls to render(Prefix)Js.+renderPrefixJs :: (JsToDoc a, JMacro a) => FastString -> a -> Doc+renderPrefixJs pfx = renderPrefixJs' defaultRenderJs pfx++renderPrefixJs' :: (JsToDoc a, JMacro a) => RenderJs -> FastString -> a -> Doc+renderPrefixJs' r pfx = jsToDocR r . jsSaturate (Just $ "jmId_" `mappend` pfx)++braceNest :: Doc -> Doc+braceNest x = char '{' <+> nest 2 x $$ char '}'++-- | Hang with braces:+--+--  hdr {+--    body+--  }+hangBrace :: Doc -> Doc -> Doc+hangBrace hdr body = sep [ hdr <> char ' ' <> char '{', nest 2 body, char '}' ]++class JsToDoc a where jsToDocR :: RenderJs -> a -> Doc+instance JsToDoc JStat where jsToDocR r = renderJsS r r+instance JsToDoc JExpr where jsToDocR r = renderJsE r r+instance JsToDoc JVal  where jsToDocR r = renderJsV r r+instance JsToDoc Ident where jsToDocR r = renderJsI r r+instance JsToDoc [JExpr] where+    jsToDocR r = vcat . map ((<> semi) . jsToDocR r)+instance JsToDoc [JStat] where+    jsToDocR r = vcat . map ((<> semi) . jsToDocR r)++defRenderJsS :: RenderJs -> JStat -> Doc+defRenderJsS r = \case+  IfStat cond x y -> hangBrace (text "if" <> parens (jsToDocR r cond))+                               (jsToDocR r x)+                     $$ mbElse+        where mbElse | y == BlockStat []  = PP.empty+                     | otherwise = hangBrace (text "else") (jsToDocR r y)+  DeclStat x Nothing  -> text "var" <+> jsToDocR r x+  DeclStat x (Just e) -> text "var" <+> jsToDocR r x <+> char '=' <+> jsToDocR r e+  WhileStat False p b -> hangBrace (text "while" <> parens (jsToDocR r p)) (jsToDocR r b)+  WhileStat True  p b -> (hangBrace (text "do") (jsToDocR r b)) $+$ text "while" <+> parens (jsToDocR r p)+  UnsatBlock e        -> jsToDocR r $ pseudoSaturate e+  BreakStat l         -> maybe (text "break")    (\(LexicalFastString s) -> (text "break"    <+> ftext s)) l+  ContinueStat l      -> maybe (text "continue") (\(LexicalFastString s) -> (text "continue" <+> ftext s)) l+  LabelStat (LexicalFastString l) s -> ftext l <> char ':' $$ printBS s+        where+          printBS (BlockStat ss) = vcat $ interSemi $ flattenBlocks ss+          printBS x = jsToDocR r x+          interSemi [x] = [jsToDocR r x]+          interSemi [] = []+          interSemi (x:xs) = (jsToDocR r x <> semi) : interSemi xs++  ForInStat each i e b -> hangBrace (text txt <> parens (jsToDocR r i <+> text "in" <+> jsToDocR r e)) (jsToDocR r b)+        where txt | each = "for each"+                  | otherwise = "for"+  SwitchStat e l d     -> hangBrace (text "switch" <+> parens (jsToDocR r e)) cases+        where l' = map (\(c,s) -> (text "case" <+> parens (jsToDocR r c) <> char ':') $$$ (jsToDocR r s)) l ++ [text "default:" $$$ (jsToDocR r d)]+              cases = vcat l'+  ReturnStat e      -> text "return" <+> jsToDocR r e+  ApplStat e es     -> jsToDocR r e <> (parens . hsep . punctuate comma $ map (jsToDocR r) es)+  TryStat s i s1 s2 -> hangBrace (text "try") (jsToDocR r s) $$ mbCatch $$ mbFinally+        where mbCatch | s1 == BlockStat [] = PP.empty+                      | otherwise = hangBrace (text "catch" <> parens (jsToDocR r i)) (jsToDocR r s1)+              mbFinally | s2 == BlockStat [] = PP.empty+                        | otherwise = hangBrace (text "finally") (jsToDocR r s2)+  AssignStat i x    -> case x of+    -- special treatment for functions, otherwise there is too much left padding+    -- (more than the length of the expression assigned to). E.g.+    --+    --    var long_variable_name = (function()+    --                               {+    --                               ...+    --                             });+    --+    ValExpr (JFunc is b) -> sep [jsToDocR r i <+> text "= function" <> parens (hsep . punctuate comma . map (jsToDocR r) $ is) <> char '{', nest 2 (jsToDocR r b), text "}"]+    _                    -> jsToDocR r i <+> char '=' <+> jsToDocR r x+  UOpStat op x+    | isPre op && isAlphaOp op -> ftext (uOpText op) <+> optParens r x+    | isPre op                 -> ftext (uOpText op) <> optParens r x+    | otherwise                -> optParens r x <> ftext (uOpText op)+  BlockStat xs -> jsToDocR r (flattenBlocks xs)++flattenBlocks :: [JStat] -> [JStat]+flattenBlocks = \case+  BlockStat y:ys -> flattenBlocks y ++ flattenBlocks ys+  y:ys           -> y : flattenBlocks ys+  []             -> []++optParens :: RenderJs -> JExpr -> Doc+optParens r x = case x of+  UOpExpr _ _ -> parens (jsToDocR r x)+  _           -> jsToDocR r x++defRenderJsE :: RenderJs -> JExpr -> Doc+defRenderJsE r = \case+  ValExpr x         -> jsToDocR r x+  SelExpr x y       -> jsToDocR r x <> char '.' <> jsToDocR r y+  IdxExpr x y       -> jsToDocR r x <> brackets (jsToDocR r y)+  IfExpr x y z      -> parens (jsToDocR r x <+> char '?' <+> jsToDocR r y <+> char ':' <+> jsToDocR r z)+  InfixExpr op x y  -> parens $ hsep [jsToDocR r x, ftext (opText op), jsToDocR r y]+  UOpExpr op x+    | isPre op && isAlphaOp op -> ftext (uOpText op) <+> optParens r x+    | isPre op                 -> ftext (uOpText op) <> optParens r x+    | otherwise                -> optParens r x <> ftext (uOpText op)+  ApplExpr je xs -> jsToDocR r je <> (parens . hsep . punctuate comma $ map (jsToDocR r) xs)+  UnsatExpr e    -> jsToDocR r $ pseudoSaturate e++defRenderJsV :: RenderJs -> JVal -> Doc+defRenderJsV r = \case+  JVar i    -> jsToDocR r i+  JList xs  -> brackets . hsep . punctuate comma $ map (jsToDocR r) xs+  JDouble (SaneDouble d)+    | d < 0 || isNegativeZero d -> parens (double d)+    | otherwise                 -> double d+  JInt i+    | i < 0     -> parens (integer i)+    | otherwise -> integer i+  JStr   s -> pprStringLit s+  JRegEx s -> hcat [char '/',ftext s, char '/']+  JHash m+    | isNullUniqMap m  -> text "{}"+    | otherwise -> braceNest . hsep . punctuate comma .+                          map (\(x,y) -> squotes (ftext x) <> colon <+> jsToDocR r y)+                          -- nonDetEltsUniqMap doesn't introduce non-determinism here+                          -- because we sort the elements lexically+                          $ sortOn (LexicalFastString . fst) (nonDetEltsUniqMap m)+  JFunc is b -> parens $ hangBrace (text "function" <> parens (hsep . punctuate comma . map (jsToDocR r) $ is)) (jsToDocR r b)+  UnsatVal f -> jsToDocR r $ pseudoSaturate f++defRenderJsI :: RenderJs -> Ident -> Doc+defRenderJsI _ (TxtI t) = ftext t+++pprStringLit :: FastString -> Doc+pprStringLit s = hcat [char '\"',encodeJson s, char '\"']++encodeJson :: FastString -> Doc+encodeJson xs = hcat (map encodeJsonChar (unpackFS xs))++encodeJsonChar :: Char -> Doc+encodeJsonChar = \case+  '/'  -> text "\\/"+  '\b' -> text "\\b"+  '\f' -> text "\\f"+  '\n' -> text "\\n"+  '\r' -> text "\\r"+  '\t' -> text "\\t"+  '"'  -> text "\\\""+  '\\' -> text "\\\\"+  c+    | not (isControl c) && ord c <= 127 -> char c+    | ord c <= 0xff   -> hexxs "\\x" 2 (ord c)+    | ord c <= 0xffff -> hexxs "\\u" 4 (ord c)+    | otherwise      -> let cp0 = ord c - 0x10000 -- output surrogate pair+                        in hexxs "\\u" 4 ((cp0 `shiftR` 10) + 0xd800) <>+                           hexxs "\\u" 4 ((cp0 .&. 0x3ff) + 0xdc00)+    where hexxs prefix pad cp =+            let h = showHex cp ""+            in  text (prefix ++ replicate (pad - length h) '0' ++ h)++uOpText :: JUOp -> FastString+uOpText = \case+  NotOp     -> "!"+  BNotOp    -> "~"+  NegOp     -> "-"+  PlusOp    -> "+"+  NewOp     -> "new"+  TypeofOp  -> "typeof"+  DeleteOp  -> "delete"+  YieldOp   -> "yield"+  VoidOp    -> "void"+  PreIncOp  -> "++"+  PostIncOp -> "++"+  PreDecOp  -> "--"+  PostDecOp -> "--"++opText :: JOp -> FastString+opText = \case+  EqOp          -> "=="+  StrictEqOp    -> "==="+  NeqOp         -> "!="+  StrictNeqOp   -> "!=="+  GtOp          -> ">"+  GeOp          -> ">="+  LtOp          -> "<"+  LeOp          -> "<="+  AddOp         -> "+"+  SubOp         -> "-"+  MulOp         -> "*"+  DivOp         -> "/"+  ModOp         -> "%"+  LeftShiftOp   -> "<<"+  RightShiftOp  -> ">>"+  ZRightShiftOp -> ">>>"+  BAndOp        -> "&"+  BOrOp         -> "|"+  BXorOp        -> "^"+  LAndOp        -> "&&"+  LOrOp         -> "||"+  InstanceofOp  -> "instanceof"+  InOp          -> "in"+++isPre :: JUOp -> Bool+isPre = \case+  PostIncOp -> False+  PostDecOp -> False+  _         -> True++isAlphaOp :: JUOp -> Bool+isAlphaOp = \case+  NewOp    -> True+  TypeofOp -> True+  DeleteOp -> True+  YieldOp  -> True+  VoidOp   -> True+  _        -> False
+ compiler/GHC/JS/Syntax.hs view
@@ -0,0 +1,392 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE PatternSynonyms #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.JS.Syntax+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+--+-- * Domain and Purpose+--+--     GHC.JS.Syntax defines the Syntax for the JS backend in GHC. It comports+--     with the [ECMA-262](https://tc39.es/ecma262/) although not every+--     production rule of the standard is represented. Code in this module is a+--     fork of [JMacro](https://hackage.haskell.org/package/jmacro) (BSD 3+--     Clause) by Gershom Bazerman, heavily modified to accomodate GHC's+--     constraints.+--+--+-- * Strategy+--+--     Nothing fancy in this module, this is a classic deeply embeded AST for+--     JS. We define numerous ADTs and pattern synonyms to make pattern matching+--     and constructing ASTs easier.+--+--+-- * Consumers+--+--     The entire JS backend consumes this module, e.g., the modules in+--     GHC.StgToJS.\*. Please see 'GHC.JS.Make' for a module which provides+--     helper functions that use the deeply embedded DSL defined in this module+--     to provide some of the benefits of a shallow embedding.+-----------------------------------------------------------------------------+module GHC.JS.Syntax+  ( -- * Deeply embedded JS datatypes+    JStat(..)+  , JExpr(..)+  , JVal(..)+  , JOp(..)+  , JUOp(..)+  , Ident(..)+  , identFS+  , JsLabel+  -- * pattern synonyms over JS operators+  , pattern New+  , pattern Not+  , pattern Negate+  , pattern Add+  , pattern Sub+  , pattern Mul+  , pattern Div+  , pattern Mod+  , pattern BOr+  , pattern BAnd+  , pattern BXor+  , pattern BNot+  , pattern LOr+  , pattern LAnd+  , pattern Int+  , pattern String+  , pattern PreInc+  , pattern PostInc+  , pattern PreDec+  , pattern PostDec+  -- * Ident supply+  , IdentSupply(..)+  , newIdentSupply+  , pseudoSaturate+  -- * Utility+  , SaneDouble(..)+  ) where++import GHC.Prelude++import Control.DeepSeq++import Data.Function+import Data.Data+import Data.Word+import qualified Data.Semigroup as Semigroup++import GHC.Generics++import GHC.Data.FastString+import GHC.Utils.Monad.State.Strict+import GHC.Types.Unique+import GHC.Types.Unique.Map++-- | A supply of identifiers, possibly empty+newtype IdentSupply a+  = IS {runIdentSupply :: State [Ident] a}+  deriving Typeable++instance NFData (IdentSupply a) where rnf IS{} = ()++inIdentSupply :: (State [Ident] a -> State [Ident] b) -> IdentSupply a -> IdentSupply b+inIdentSupply f x = IS $ f (runIdentSupply x)++instance Functor IdentSupply where+    fmap f x = inIdentSupply (fmap f) x++newIdentSupply :: Maybe FastString -> [Ident]+newIdentSupply Nothing    = newIdentSupply (Just "jmId")+newIdentSupply (Just pfx) = [ TxtI (mconcat [pfx,"_",mkFastString (show x)])+                            | x <- [(0::Word64)..]+                            ]++-- | Given a Pseudo-saturate a value with garbage @<<unsatId>>@ identifiers.+pseudoSaturate :: IdentSupply a -> a+pseudoSaturate x = evalState (runIdentSupply x) $ newIdentSupply (Just "<<unsatId>>")++instance Eq a => Eq (IdentSupply a) where+    (==) = (==) `on` pseudoSaturate+instance Ord a => Ord (IdentSupply a) where+    compare = compare `on` pseudoSaturate+instance Show a => Show (IdentSupply a) where+    show x = "(" ++ show (pseudoSaturate x) ++ ")"+++--------------------------------------------------------------------------------+--                            Statements+--------------------------------------------------------------------------------+-- | JavaScript statements, see the [ECMA262+-- Reference](https://tc39.es/ecma262/#sec-ecmascript-language-statements-and-declarations)+-- for details+data JStat+  = DeclStat   !Ident !(Maybe JExpr)         -- ^ Variable declarations: var foo [= e]+  | ReturnStat JExpr                         -- ^ Return+  | IfStat     JExpr JStat JStat             -- ^ If+  | WhileStat  Bool JExpr JStat              -- ^ While, bool is "do" when True+  | ForInStat  Bool Ident JExpr JStat        -- ^ For-in, bool is "each' when True+  | SwitchStat JExpr [(JExpr, JStat)] JStat  -- ^ Switch+  | TryStat    JStat Ident JStat JStat       -- ^ Try+  | BlockStat  [JStat]                       -- ^ Blocks+  | ApplStat   JExpr [JExpr]                 -- ^ Application+  | UOpStat JUOp JExpr                       -- ^ Unary operators+  | AssignStat JExpr JExpr                   -- ^ Binding form: @foo = bar@+  | UnsatBlock (IdentSupply JStat)           -- ^ /Unsaturated/ blocks see 'pseudoSaturate'+  | LabelStat JsLabel JStat                  -- ^ Statement Labels, makes me nostalgic for qbasic+  | BreakStat (Maybe JsLabel)                -- ^ Break+  | ContinueStat (Maybe JsLabel)             -- ^ Continue+  deriving (Eq, Typeable, Generic)++-- | A Label used for 'JStat', specifically 'BreakStat', 'ContinueStat' and of+-- course 'LabelStat'+type JsLabel = LexicalFastString++instance Semigroup JStat where+  (<>) = appendJStat++instance Monoid JStat where+  mempty = BlockStat []++-- | Append a statement to another statement. 'appendJStat' only returns a+-- 'JStat' that is /not/ a 'BlockStat' when either @mx@ or @my is an empty+-- 'BlockStat'. That is:+-- > (BlockStat [] , y           ) = y+-- > (x            , BlockStat []) = x+appendJStat :: JStat -> JStat -> JStat+appendJStat mx my = case (mx,my) of+  (BlockStat [] , y           ) -> y+  (x            , BlockStat []) -> x+  (BlockStat xs , BlockStat ys) -> BlockStat $ xs ++ ys+  (BlockStat xs , ys          ) -> BlockStat $ xs ++ [ys]+  (xs           , BlockStat ys) -> BlockStat $ xs : ys+  (xs           , ys          ) -> BlockStat [xs,ys]+++--------------------------------------------------------------------------------+--                            Expressions+--------------------------------------------------------------------------------+-- | JavaScript Expressions+data JExpr+  = ValExpr    JVal                 -- ^ All values are trivially expressions+  | SelExpr    JExpr Ident          -- ^ Selection: Obj.foo, see 'GHC.JS.Make..^'+  | IdxExpr    JExpr JExpr          -- ^ Indexing:  Obj[foo], see 'GHC.JS.Make..!'+  | InfixExpr  JOp JExpr JExpr      -- ^ Infix Expressions, see 'JExpr'+                                    --   pattern synonyms+  | UOpExpr    JUOp JExpr           -- ^ Unary Expressions+  | IfExpr     JExpr JExpr JExpr    -- ^ If-expression+  | ApplExpr   JExpr [JExpr]        -- ^ Application+  | UnsatExpr  (IdentSupply JExpr)  -- ^ An /Unsaturated/ expression.+                                    --   See 'pseudoSaturate'+  deriving (Eq, Typeable, Generic)++-- * Useful pattern synonyms to ease programming with the deeply embedded JS+--   AST. Each pattern wraps @JUOp@ and @JOp@ into a @JExpr@s to save typing and+--   for convienience. In addition we include a string wrapper for JS string+--   and Integer literals.++-- | pattern synonym for a unary operator new+pattern New :: JExpr -> JExpr+pattern New x = UOpExpr NewOp x++-- | pattern synonym for prefix increment @++x@+pattern PreInc :: JExpr -> JExpr+pattern PreInc x = UOpExpr PreIncOp x++-- | pattern synonym for postfix increment @x++@+pattern PostInc :: JExpr -> JExpr+pattern PostInc x = UOpExpr PostIncOp x++-- | pattern synonym for prefix decrement @--x@+pattern PreDec :: JExpr -> JExpr+pattern PreDec x = UOpExpr PreDecOp x++-- | pattern synonym for postfix decrement @--x@+pattern PostDec :: JExpr -> JExpr+pattern PostDec x = UOpExpr PostDecOp x++-- | pattern synonym for logical not @!@+pattern Not :: JExpr -> JExpr+pattern Not x = UOpExpr NotOp x++-- | pattern synonym for unary negation @-@+pattern Negate :: JExpr -> JExpr+pattern Negate x = UOpExpr NegOp x++-- | pattern synonym for addition @+@+pattern Add :: JExpr -> JExpr -> JExpr+pattern Add x y = InfixExpr AddOp x y++-- | pattern synonym for subtraction @-@+pattern Sub :: JExpr -> JExpr -> JExpr+pattern Sub x y = InfixExpr SubOp x y++-- | pattern synonym for multiplication @*@+pattern Mul :: JExpr -> JExpr -> JExpr+pattern Mul x y = InfixExpr MulOp x y++-- | pattern synonym for division @*@+pattern Div :: JExpr -> JExpr -> JExpr+pattern Div x y = InfixExpr DivOp x y++-- | pattern synonym for remainder @%@+pattern Mod :: JExpr -> JExpr -> JExpr+pattern Mod x y = InfixExpr ModOp x y++-- | pattern synonym for Bitwise Or @|@+pattern BOr :: JExpr -> JExpr -> JExpr+pattern BOr x y = InfixExpr BOrOp x y++-- | pattern synonym for Bitwise And @&@+pattern BAnd :: JExpr -> JExpr -> JExpr+pattern BAnd x y = InfixExpr BAndOp x y++-- | pattern synonym for Bitwise XOr @^@+pattern BXor :: JExpr -> JExpr -> JExpr+pattern BXor x y = InfixExpr BXorOp x y++-- | pattern synonym for Bitwise Not @~@+pattern BNot :: JExpr -> JExpr+pattern BNot x = UOpExpr BNotOp x++-- | pattern synonym for logical Or @||@+pattern LOr :: JExpr -> JExpr -> JExpr+pattern LOr x y = InfixExpr LOrOp x y++-- | pattern synonym for logical And @&&@+pattern LAnd :: JExpr -> JExpr -> JExpr+pattern LAnd x y = InfixExpr LAndOp x y+++-- | pattern synonym to create integer values+pattern Int :: Integer -> JExpr+pattern Int x = ValExpr (JInt x)++-- | pattern synonym to create string values+pattern String :: FastString -> JExpr+pattern String x = ValExpr (JStr x)+++--------------------------------------------------------------------------------+--                            Values+--------------------------------------------------------------------------------+-- | JavaScript values+data JVal+  = JVar     Ident                      -- ^ A variable reference+  | JList    [JExpr]                    -- ^ A JavaScript list, or what JS+                                        --   calls an Array+  | JDouble  SaneDouble                 -- ^ A Double+  | JInt     Integer                    -- ^ A BigInt+  | JStr     FastString                 -- ^ A String+  | JRegEx   FastString                 -- ^ A Regex+  | JHash    (UniqMap FastString JExpr) -- ^ A JS HashMap: @{"foo": 0}@+  | JFunc    [Ident] JStat              -- ^ A function+  | UnsatVal (IdentSupply JVal)         -- ^ An /Unsaturated/ value, see 'pseudoSaturate'+  deriving (Eq, Typeable, Generic)++--------------------------------------------------------------------------------+--                            Operators+--------------------------------------------------------------------------------+-- | JS Binary Operators. We do not deeply embed the comma operator and the+-- assignment operators+data JOp+  = EqOp            -- ^ Equality:              `==`+  | StrictEqOp      -- ^ Strict Equality:       `===`+  | NeqOp           -- ^ InEquality:            `!=`+  | StrictNeqOp     -- ^ Strict InEquality      `!==`+  | GtOp            -- ^ Greater Than:          `>`+  | GeOp            -- ^ Greater Than or Equal: `>=`+  | LtOp            -- ^ Less Than:              <+  | LeOp            -- ^ Less Than or Equal:     <=+  | AddOp           -- ^ Addition:               ++  | SubOp           -- ^ Subtraction:            -+  | MulOp           -- ^ Multiplication          \*+  | DivOp           -- ^ Division:               \/+  | ModOp           -- ^ Remainder:              %+  | LeftShiftOp     -- ^ Left Shift:             \<\<+  | RightShiftOp    -- ^ Right Shift:            \>\>+  | ZRightShiftOp   -- ^ Unsigned RightShift:    \>\>\>+  | BAndOp          -- ^ Bitwise And:            &+  | BOrOp           -- ^ Bitwise Or:             |+  | BXorOp          -- ^ Bitwise XOr:            ^+  | LAndOp          -- ^ Logical And:            &&+  | LOrOp           -- ^ Logical Or:             ||+  | InstanceofOp    -- ^ @instanceof@+  | InOp            -- ^ @in@+  deriving (Show, Eq, Ord, Enum, Data, Typeable, Generic)++instance NFData JOp++-- | JS Unary Operators+data JUOp+  = NotOp           -- ^ Logical Not: @!@+  | BNotOp          -- ^ Bitwise Not: @~@+  | NegOp           -- ^ Negation:    @-@+  | PlusOp          -- ^ Unary Plus:  @+x@+  | NewOp           -- ^ new    x+  | TypeofOp        -- ^ typeof x+  | DeleteOp        -- ^ delete x+  | YieldOp         -- ^ yield  x+  | VoidOp          -- ^ void   x+  | PreIncOp        -- ^ Prefix Increment:  @++x@+  | PostIncOp       -- ^ Postfix Increment: @x++@+  | PreDecOp        -- ^ Prefix Decrement:  @--x@+  | PostDecOp       -- ^ Postfix Decrement: @x--@+  deriving (Show, Eq, Ord, Enum, Data, Typeable, Generic)++instance NFData JUOp++-- | A newtype wrapper around 'Double' to ensure we never generate a 'Double'+-- that becomes a 'NaN', see 'Eq SaneDouble', 'Ord SaneDouble' for details on+-- Sane-ness+newtype SaneDouble = SaneDouble+  { unSaneDouble :: Double+  }+  deriving (Data, Typeable, Fractional, Num, Generic, NFData)++instance Eq SaneDouble where+    (SaneDouble x) == (SaneDouble y) = x == y || (isNaN x && isNaN y)++instance Ord SaneDouble where+    compare (SaneDouble x) (SaneDouble y) = compare (fromNaN x) (fromNaN y)+        where fromNaN z | isNaN z = Nothing+                        | otherwise = Just z++instance Show SaneDouble where+    show (SaneDouble x) = show x+++--------------------------------------------------------------------------------+--                            Identifiers+--------------------------------------------------------------------------------+-- We use FastString for identifiers in JS backend++-- | A newtype wrapper around 'FastString' for JS identifiers.+newtype Ident = TxtI { itxt :: FastString }+ deriving stock   (Show, Eq)+ deriving newtype (Uniquable)++identFS :: Ident -> FastString+identFS = \case+  TxtI fs -> fs
+ compiler/GHC/JS/Transform.hs view
@@ -0,0 +1,264 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE BlockArguments #-}++module GHC.JS.Transform+  ( mapIdent+  , mapStatIdent+  , mapExprIdent+  , identsS+  , identsV+  , identsE+  -- * Saturation+  , jsSaturate+  -- * Generic traversal (via compos)+  , JMacro(..)+  , JMGadt(..)+  , Compos(..)+  , composOp+  , composOpM+  , composOpM_+  , composOpFold+  )+where++import GHC.Prelude++import GHC.JS.Syntax++import Data.Functor.Identity+import Control.Monad+import Data.Bifunctor++import GHC.Data.FastString+import GHC.Utils.Monad.State.Strict+import GHC.Types.Unique.Map++mapExprIdent :: (Ident -> JExpr) -> JExpr -> JExpr+mapExprIdent f = fst (mapIdent f)++mapStatIdent :: (Ident -> JExpr) -> JStat -> JStat+mapStatIdent f = snd (mapIdent f)++-- | Map on every variable ident+mapIdent :: (Ident -> JExpr) -> (JExpr -> JExpr, JStat -> JStat)+mapIdent f = (map_expr, map_stat)+  where+    map_expr = \case+      ValExpr    v        -> map_val v+      SelExpr    e i      -> SelExpr (map_expr e) i+      IdxExpr    e1 e2    -> IdxExpr (map_expr e1) (map_expr e2)+      InfixExpr  o e1 e2  -> InfixExpr o (map_expr e1) (map_expr e2)+      UOpExpr    o e      -> UOpExpr o (map_expr e)+      IfExpr     e1 e2 e3 -> IfExpr (map_expr e1) (map_expr e2) (map_expr e3)+      ApplExpr   e es     -> ApplExpr (map_expr e) (fmap map_expr es)+      UnsatExpr  me       -> UnsatExpr (fmap map_expr me)++    map_val v = case v of+      JVar     i  -> f i+      JList    es -> ValExpr $ JList (fmap map_expr es)+      JDouble{}   -> ValExpr $ v+      JInt{}      -> ValExpr $ v+      JStr{}      -> ValExpr $ v+      JRegEx{}    -> ValExpr $ v+      JHash me    -> ValExpr $ JHash (fmap map_expr me)+      JFunc is s  -> ValExpr $ JFunc is (map_stat s)+      UnsatVal v2 -> ValExpr $ UnsatVal v2++    map_stat s = case s of+      DeclStat i e          -> DeclStat i (fmap map_expr e)+      ReturnStat e          -> ReturnStat (map_expr e)+      IfStat     e s1 s2    -> IfStat (map_expr e) (map_stat s1) (map_stat s2)+      WhileStat  b e s2     -> WhileStat b (map_expr e) (map_stat s2)+      ForInStat  b i e s2   -> ForInStat b i (map_expr e) (map_stat s2)+      SwitchStat e les s2   -> SwitchStat (map_expr e) (fmap (bimap map_expr map_stat) les) (map_stat s2)+      TryStat    s2 i s3 s4 -> TryStat (map_stat s2) i (map_stat s3) (map_stat s4)+      BlockStat  ls         -> BlockStat (fmap map_stat ls)+      ApplStat   e es       -> ApplStat (map_expr e) (fmap map_expr es)+      UOpStat    o e        -> UOpStat o (map_expr e)+      AssignStat e1 e2      -> AssignStat (map_expr e1) (map_expr e2)+      UnsatBlock ms         -> UnsatBlock (fmap map_stat ms)+      LabelStat  l s2       -> LabelStat l (map_stat s2)+      BreakStat{}           -> s+      ContinueStat{}        -> s++{-# INLINE identsS #-}+identsS :: JStat -> [Ident]+identsS = \case+  DeclStat i e       -> [i] ++ maybe [] identsE e+  ReturnStat e       -> identsE e+  IfStat e s1 s2     -> identsE e ++ identsS s1 ++ identsS s2+  WhileStat _ e s    -> identsE e ++ identsS s+  ForInStat _ i e s  -> [i] ++ identsE e ++ identsS s+  SwitchStat e xs s  -> identsE e ++ concatMap traverseCase xs ++ identsS s+                          where traverseCase (e,s) = identsE e ++ identsS s+  TryStat s1 i s2 s3 -> identsS s1 ++ [i] ++ identsS s2 ++ identsS s3+  BlockStat xs       -> concatMap identsS xs+  ApplStat e es      -> identsE e ++ concatMap identsE es+  UOpStat _op e      -> identsE e+  AssignStat e1 e2   -> identsE e1 ++ identsE e2+  UnsatBlock{}       -> error "identsS: UnsatBlock"+  LabelStat _l s     -> identsS s+  BreakStat{}        -> []+  ContinueStat{}     -> []++{-# INLINE identsE #-}+identsE :: JExpr -> [Ident]+identsE = \case+  ValExpr v         -> identsV v+  SelExpr e _i      -> identsE e -- do not rename properties+  IdxExpr e1 e2     -> identsE e1 ++ identsE e2+  InfixExpr _ e1 e2 -> identsE e1 ++ identsE e2+  UOpExpr _ e       -> identsE e+  IfExpr e1 e2 e3   -> identsE e1 ++ identsE e2 ++ identsE e3+  ApplExpr e es     -> identsE e  ++ concatMap identsE es+  UnsatExpr{}       -> error "identsE: UnsatExpr"++{-# INLINE identsV #-}+identsV :: JVal -> [Ident]+identsV = \case+  JVar i       -> [i]+  JList xs     -> concatMap identsE xs+  JDouble{}    -> []+  JInt{}       -> []+  JStr{}       -> []+  JRegEx{}     -> []+  JHash m      -> concatMap (identsE . snd) (nonDetEltsUniqMap m)+  JFunc args s -> args ++ identsS s+  UnsatVal{}   -> error "identsV: UnsatVal"+++{--------------------------------------------------------------------+  Compos+--------------------------------------------------------------------}+-- | Compos and ops for generic traversal as defined over+-- the JMacro ADT.++-- | Utility class to coerce the ADT into a regular structure.++class JMacro a where+    jtoGADT :: a -> JMGadt a+    jfromGADT :: JMGadt a -> a++instance JMacro Ident where+    jtoGADT = JMGId+    jfromGADT (JMGId x) = x++instance JMacro JStat where+    jtoGADT = JMGStat+    jfromGADT (JMGStat x) = x++instance JMacro JExpr where+    jtoGADT = JMGExpr+    jfromGADT (JMGExpr x) = x++instance JMacro JVal where+    jtoGADT = JMGVal+    jfromGADT (JMGVal x) = x++-- | Union type to allow regular traversal by compos.+data JMGadt a where+    JMGId   :: Ident -> JMGadt Ident+    JMGStat :: JStat -> JMGadt JStat+    JMGExpr :: JExpr -> JMGadt JExpr+    JMGVal  :: JVal  -> JMGadt JVal++composOp :: Compos t => (forall a. t a -> t a) -> t b -> t b+composOp f = runIdentity . composOpM (Identity . f)++composOpM :: (Compos t, Monad m) => (forall a. t a -> m (t a)) -> t b -> m (t b)+composOpM = compos return ap++composOpM_ :: (Compos t, Monad m) => (forall a. t a -> m ()) -> t b -> m ()+composOpM_ = composOpFold (return ()) (>>)++composOpFold :: Compos t => b -> (b -> b -> b) -> (forall a. t a -> b) -> t c -> b+composOpFold z c f = unC . compos (\_ -> C z) (\(C x) (C y) -> C (c x y)) (C . f)++newtype C b a = C { unC :: b }++class Compos t where+    compos :: (forall a. a -> m a) -> (forall a b. m (a -> b) -> m a -> m b)+           -> (forall a. t a -> m (t a)) -> t c -> m (t c)++instance Compos JMGadt where+    compos = jmcompos++jmcompos :: forall m c. (forall a. a -> m a) -> (forall a b. m (a -> b) -> m a -> m b) -> (forall a. JMGadt a -> m (JMGadt a)) -> JMGadt c -> m (JMGadt c)+jmcompos ret app f' v =+    case v of+     JMGId _ -> ret v+     JMGStat v' -> ret JMGStat `app` case v' of+           DeclStat i e -> ret DeclStat `app` f i `app` mapMaybeM' f e+           ReturnStat i -> ret ReturnStat `app` f i+           IfStat e s s' -> ret IfStat `app` f e `app` f s `app` f s'+           WhileStat b e s -> ret (WhileStat b) `app` f e `app` f s+           ForInStat b i e s -> ret (ForInStat b) `app` f i `app` f e `app` f s+           SwitchStat e l d -> ret SwitchStat `app` f e `app` l' `app` f d+               where l' = mapM' (\(c,s) -> ret (,) `app` f c `app` f s) l+           BlockStat xs -> ret BlockStat `app` mapM' f xs+           ApplStat  e xs -> ret ApplStat `app` f e `app` mapM' f xs+           TryStat s i s1 s2 -> ret TryStat `app` f s `app` f i `app` f s1 `app` f s2+           UOpStat o e -> ret (UOpStat o) `app` f e+           AssignStat e e' -> ret AssignStat `app` f e `app` f e'+           UnsatBlock _ -> ret v'+           ContinueStat l -> ret (ContinueStat l)+           BreakStat l -> ret (BreakStat l)+           LabelStat l s -> ret (LabelStat l) `app` f s+     JMGExpr v' -> ret JMGExpr `app` case v' of+           ValExpr e -> ret ValExpr `app` f e+           SelExpr e e' -> ret SelExpr `app` f e `app` f e'+           IdxExpr e e' -> ret IdxExpr `app` f e `app` f e'+           InfixExpr o e e' -> ret (InfixExpr o) `app` f e `app` f e'+           UOpExpr o e -> ret (UOpExpr o) `app` f e+           IfExpr e e' e'' -> ret IfExpr `app` f e `app` f e' `app` f e''+           ApplExpr e xs -> ret ApplExpr `app` f e `app` mapM' f xs+           UnsatExpr _ -> ret v'+     JMGVal v' -> ret JMGVal `app` case v' of+           JVar i -> ret JVar `app` f i+           JList xs -> ret JList `app` mapM' f xs+           JDouble _ -> ret v'+           JInt    _ -> ret v'+           JStr    _ -> ret v'+           JRegEx  _ -> ret v'+           JHash   m -> ret JHash `app` m'+               -- nonDetEltsUniqMap doesn't introduce nondeterminism here because the+               -- elements are treated independently before being re-added to a UniqMap+               where (ls, vs) = unzip (nonDetEltsUniqMap m)+                     m' = ret (listToUniqMap . zip ls) `app` mapM' f vs+           JFunc xs s -> ret JFunc `app` mapM' f xs `app` f s+           UnsatVal _ -> ret v'++  where+    mapM' :: forall a. (a -> m a) -> [a] -> m [a]+    mapM' g = foldr (app . app (ret (:)) . g) (ret [])+    mapMaybeM' :: forall a. (a -> m a) -> Maybe a -> m (Maybe a)+    mapMaybeM' g = \case+      Nothing -> ret Nothing+      Just a  -> app (ret Just) (g a)+    f :: forall b. JMacro b => b -> m b+    f x = ret jfromGADT `app` f' (jtoGADT x)++{--------------------------------------------------------------------+  Saturation+--------------------------------------------------------------------}++-- | Given an optional prefix, fills in all free variable names with a supply+-- of names generated by the prefix.+jsSaturate :: (JMacro a) => Maybe FastString -> a -> a+jsSaturate str x = evalState (runIdentSupply $ jsSaturate_ x) (newIdentSupply str)++jsSaturate_ :: (JMacro a) => a -> IdentSupply a+jsSaturate_ e = IS $ jfromGADT <$> go (jtoGADT e)+    where+      go :: forall a. JMGadt a -> State [Ident] (JMGadt a)+      go v = case v of+               JMGStat (UnsatBlock us) -> go =<< (JMGStat <$> runIdentSupply us)+               JMGExpr (UnsatExpr  us) -> go =<< (JMGExpr <$> runIdentSupply us)+               JMGVal  (UnsatVal   us) -> go =<< (JMGVal  <$> runIdentSupply us)+               _ -> composOpM go v
compiler/GHC/Linker/Static.hs view
@@ -64,23 +64,27 @@ -}  linkBinary :: Logger -> TmpFs -> DynFlags -> UnitEnv -> [FilePath] -> [UnitId] -> IO ()-linkBinary logger tmpfs dflags unit_env o_files dep_units = do+linkBinary = linkBinary' False++linkBinary' :: Bool -> Logger -> TmpFs -> DynFlags -> UnitEnv -> [FilePath] -> [UnitId] -> IO ()+linkBinary' staticLink logger tmpfs dflags unit_env o_files dep_units = do     let platform   = ue_platform unit_env         unit_state = ue_units unit_env         toolSettings' = toolSettings dflags         verbFlags = getVerbFlags dflags-        output_fn = exeFileName platform False (outputFile_ dflags)+        arch_os   = platformArchOS platform+        output_fn = exeFileName arch_os staticLink (outputFile_ dflags)         namever   = ghcNameVersion dflags         ways_     = ways dflags -    -- get the full list of packages to link with, by combining the-    -- explicit packages with the auto packages and all of their-    -- dependencies, and eliminating duplicates.-     full_output_fn <- if isAbsolute output_fn                       then return output_fn                       else do d <- getCurrentDirectory                               return $ normalise (d </> output_fn)++    -- get the full list of packages to link with, by combining the+    -- explicit packages with the auto packages and all of their+    -- dependencies, and eliminating duplicates.     pkgs <- mayThrowUnitErr (preloadUnitsInfo' unit_env dep_units)     let pkg_lib_paths     = collectLibraryDirs ways_ pkgs     let pkg_lib_path_opts = concatMap get_pkg_lib_path_opts pkg_lib_paths@@ -267,7 +271,8 @@   let platform  = ue_platform unit_env       extra_ld_inputs = [ f | FileOption _ f <- ldInputs dflags ]       modules = o_files ++ extra_ld_inputs-      output_fn = exeFileName platform True (outputFile_ dflags)+      arch_os = platformArchOS platform+      output_fn = exeFileName arch_os True (outputFile_ dflags)       namever = ghcNameVersion dflags       ways_   = ways dflags 
compiler/GHC/Llvm/Ppr.hs view
@@ -517,8 +517,8 @@ ppPlainName :: LlvmCgConfig -> LlvmVar -> SDoc ppPlainName opts v = case v of    (LMGlobalVar x _ _ _ _ _) -> ftext x-   (LMLocalVar  x LMLabel  ) -> text (show x)-   (LMLocalVar  x _        ) -> text ('l' : show x)+   (LMLocalVar  x LMLabel  ) -> pprUniqueAlways x+   (LMLocalVar  x _        ) -> char 'l' <> pprUniqueAlways x    (LMNLocalVar x _        ) -> ftext x    (LMLitVar    x          ) -> ppLit opts x 
compiler/GHC/Rename/Bind.hs view
@@ -3,7 +3,6 @@ {-# LANGUAGE TypeFamilies #-}  {-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}-{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}  {- (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
compiler/GHC/Rename/Expr.hs view
@@ -6,6 +6,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications    #-} {-# LANGUAGE TypeFamilies        #-}+{-# LANGUAGE ViewPatterns        #-}  {-# OPTIONS_GHC -Wno-incomplete-record-updates #-} {-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}@@ -24,10 +25,11 @@  module GHC.Rename.Expr (         rnLExpr, rnExpr, rnStmts, mkExpandedExpr,-        AnnoBody+        AnnoBody, UnexpectedStatement(..)    ) where  import GHC.Prelude+import GHC.Data.FastString  import GHC.Rename.Bind ( rnLocalBindsAndThen, rnLocalValBindsLHS, rnLocalValBindsRHS                         , rnMatchGroup, rnGRHS, makeMiniFixityEnv)@@ -55,7 +57,6 @@  import GHC.Types.FieldLabel import GHC.Types.Fixity-import GHC.Types.Hint (suggestExtension) import GHC.Types.Id.Make import GHC.Types.Name import GHC.Types.Name.Set@@ -76,7 +77,7 @@ import Language.Haskell.Syntax.Basic (FieldLabelString(..))  import Data.List (unzip4, minimumBy)-import Data.List.NonEmpty ( NonEmpty(..) )+import Data.List.NonEmpty ( NonEmpty(..), nonEmpty ) import Data.Maybe (isJust, isNothing) import Control.Arrow (first) import Data.Ord@@ -484,13 +485,11 @@             }       Right flds ->  -- 'OverloadedRecordUpdate' is in effect. Record dot update desugaring.         do { ; unlessXOptM LangExt.RebindableSyntax $-                 addErr $ mkTcRnUnknownMessage $ mkPlainError noHints $-                   text "RebindableSyntax is required if OverloadedRecordUpdate is enabled."+                 addErr TcRnNoRebindableSyntaxRecordDot              ; let punnedFields = [fld | (L _ fld) <- flds, hfbPun fld]              ; punsEnabled <-xoptM LangExt.NamedFieldPuns              ; unless (null punnedFields || punsEnabled) $-                 addErr $ mkTcRnUnknownMessage $ mkPlainError noHints $-                   text "For this to work enable NamedFieldPuns."+                 addErr TcRnNoFieldPunsRecordDot              ; (getField, fv_getField) <- lookupSyntaxName getFieldName              ; (setField, fv_setField) <- lookupSyntaxName setFieldName              ; (e, fv_e) <- rnLExpr expr@@ -565,17 +564,11 @@     -- absolutely prepared to cope with static forms, we check for     -- -XStaticPointers here as well.     unlessXOptM LangExt.StaticPointers $-      addErr $ mkTcRnUnknownMessage $ mkPlainError noHints $-        hang (text "Illegal static expression:" <+> ppr e)-                  2 (text "Use StaticPointers to enable this extension")+      addErr $ TcRnIllegalStaticExpression e     (expr',fvExpr) <- rnLExpr expr     stage <- getStage     case stage of-      Splice _ -> addErr $ mkTcRnUnknownMessage $-                    mkPlainError noHints $ sep-                      [ text "static forms cannot be used in splices:"-                      , nest 2 $ ppr e-                      ]+      Splice _ -> addErr $ TcRnIllegalStaticFormInSplice e       _ -> return ()     mod <- getModule     let fvExpr' = filterNameSet (nameIsLocalOrFrom mod) fvExpr@@ -1021,9 +1014,6 @@  type AnnoBody body   = ( Outputable (body GhcPs)-    , Anno (StmtLR GhcPs GhcPs (LocatedA (body GhcPs))) ~ SrcSpanAnnA-    , Anno (StmtLR GhcRn GhcPs (LocatedA (body GhcPs))) ~ SrcSpanAnnA-    , Anno (StmtLR GhcRn GhcRn (LocatedA (body GhcRn))) ~ SrcSpanAnnA     )  -- | Rename some Stmts@@ -1088,15 +1078,13 @@        ; (thing, fvs) <- thing_inside []        ; return (([], thing), fvs) } -rnStmtsWithFreeVars mDoExpr@(HsDoStmt MDoExpr{}) rnBody stmts thing_inside    -- Deal with mdo+rnStmtsWithFreeVars mDoExpr@(HsDoStmt MDoExpr{}) rnBody (nonEmpty -> Just stmts) thing_inside    -- Deal with mdo   = -- Behave like do { rec { ...all but last... }; last }     do { ((stmts1, (stmts2, thing)), fvs)-           <- rnStmt mDoExpr rnBody (noLocA $ mkRecStmt noAnn (noLocA all_but_last)) $ \ _ ->-              do { last_stmt' <- checkLastStmt mDoExpr last_stmt+           <- rnStmt mDoExpr rnBody (noLocA $ mkRecStmt noAnn (noLocA (NE.init stmts))) $ \ _ ->+              do { last_stmt' <- checkLastStmt mDoExpr (NE.last stmts)                  ; rnStmt mDoExpr rnBody last_stmt' thing_inside }         ; return (((stmts1 ++ stmts2), thing), fvs) }-  where-    Just (all_but_last, last_stmt) = snocView stmts  rnStmtsWithFreeVars ctxt rnBody (lstmt@(L loc _) : lstmts) thing_inside   | null lstmts@@ -1108,7 +1096,7 @@   = do { ((stmts1, (stmts2, thing)), fvs)             <- setSrcSpanA loc                  $                do { checkStmt ctxt lstmt-                  ; rnStmt ctxt rnBody lstmt    $ \ bndrs1 ->+                  ; rnStmt ctxt rnBody lstmt $ \ bndrs1 ->                     rnStmtsWithFreeVars ctxt rnBody lstmts  $ \ bndrs2 ->                     thing_inside (bndrs1 ++ bndrs2) }         ; return (((stmts1 ++ stmts2), thing), fvs) }@@ -1312,9 +1300,7 @@            ; return ((seg':segs', thing), fvs) }      cmpByOcc n1 n2 = nameOccName n1 `compare` nameOccName n2-    dupErr vs = addErr $ mkTcRnUnknownMessage $ mkPlainError noHints $-                  (text "Duplicate binding in parallel list comprehension for:"-                    <+> quotes (ppr (NE.head vs)))+    dupErr vs = addErr $ TcRnListComprehensionDuplicateBinding (NE.head vs)  lookupQualifiedDoStmtName :: HsStmtContext GhcRn -> Name -> RnM (SyntaxExpr GhcRn, FreeVars) -- Like lookupStmtName, but respects QualifiedDo@@ -1403,8 +1389,8 @@   -- wrapper that does both the left- and right-hand sides-rnRecStmtsAndThen :: AnnoBody body =>-                     HsStmtContext GhcRn+rnRecStmtsAndThen :: AnnoBody body+                  => HsStmtContext GhcRn                   -> (body GhcPs -> RnM (body GhcRn, FreeVars))                   -> [LStmt GhcPs (LocatedA (body GhcPs))]                          -- assumes that the FreeVars returned includes@@ -1467,8 +1453,9 @@       return [(L loc (BindStmt noAnn pat' body), fv_pat)]  rn_rec_stmt_lhs _ (L _ (LetStmt _ binds@(HsIPBinds {})))-  = failWith (badIpBinds (text "an mdo expression") binds)+  = failWith (badIpBinds (Left binds)) + rn_rec_stmt_lhs fix_env (L loc (LetStmt _ (HsValBinds x binds)))     = do (_bound_names, binds') <- rnLocalValBindsLHS fix_env binds          return [(L loc (LetStmt noAnn (HsValBinds x binds')),@@ -1541,7 +1528,7 @@                   L loc (BindStmt xbsrn pat' (L lb body')))] }  rn_rec_stmt _ _ _ (L _ (LetStmt _ binds@(HsIPBinds {})), _)-  = failWith (badIpBinds (text "an mdo expression") binds)+  = failWith (badIpBinds (Right binds))  rn_rec_stmt _ _ all_bndrs (L loc (LetStmt _ (HsValBinds x binds')), _)   = do { (binds', du_binds) <- rnLocalValBindsRHS (mkNameSet all_bndrs) binds'@@ -1566,8 +1553,8 @@ rn_rec_stmt _ _ _ stmt@(L _ (ApplicativeStmt {}), _)   = pprPanic "rn_rec_stmt: ApplicativeStmt" (ppr stmt) -rn_rec_stmts :: AnnoBody body =>-                HsStmtContext GhcRn+rn_rec_stmts :: AnnoBody body+             => HsStmtContext GhcRn              -> (body GhcPs -> RnM (body GhcRn, FreeVars))              -> [Name]              -> [(LStmtLR GhcRn GhcPs (LocatedA (body GhcPs)), FreeVars)]@@ -1577,8 +1564,7 @@        ; return (concat segs_s) }  ----------------------------------------------segmentRecStmts :: AnnoBody body-                => SrcSpan -> HsStmtContext GhcRn+segmentRecStmts :: SrcSpan -> HsStmtContext GhcRn                 -> Stmt GhcRn (LocatedA (body GhcRn))                 -> [Segment (LStmt GhcRn (LocatedA (body GhcRn)))]                 -> (FreeVars, Bool)@@ -2457,24 +2443,18 @@ checkEmptyStmts :: HsStmtContext GhcRn -> RnM () -- We've seen an empty sequence of Stmts... is that ok? checkEmptyStmts ctxt-  = unless (okEmpty ctxt) (addErr (emptyErr ctxt))--okEmpty :: HsStmtContext a -> Bool-okEmpty (PatGuard {}) = True-okEmpty _             = False--emptyErr :: HsStmtContext GhcRn -> TcRnMessage-emptyErr (ParStmtCtxt {})   = mkTcRnUnknownMessage $ mkPlainError noHints $-  text "Empty statement group in parallel comprehension"-emptyErr (TransStmtCtxt {}) = mkTcRnUnknownMessage $ mkPlainError noHints $-  text "Empty statement group preceding 'group' or 'then'"-emptyErr ctxt@(HsDoStmt _)  = mkTcRnUnknownMessage $ mkPlainError [suggestExtension LangExt.NondecreasingIndentation] $-  text "Empty" <+> pprStmtContext ctxt-emptyErr ctxt               = mkTcRnUnknownMessage $ mkPlainError noHints $-  text "Empty" <+> pprStmtContext ctxt+  = mapM_ (addErr . TcRnEmptyStmtsGroup) mb_err+  where+    mb_err = case ctxt of+      PatGuard {}      -> Nothing -- Pattern guards can be empty+      ParStmtCtxt {}   -> Just EmptyStmtsGroupInParallelComp+      TransStmtCtxt {} -> Just EmptyStmtsGroupInTransformListComp+      HsDoStmt flav    -> Just $ EmptyStmtsGroupInDoNotation flav+      ArrowExpr        -> Just EmptyStmtsGroupInArrowNotation  -----------------------checkLastStmt :: AnnoBody body => HsStmtContext GhcRn+checkLastStmt :: AnnoBody body+              => HsStmtContext GhcRn               -> LStmt GhcPs (LocatedA (body GhcPs))               -> RnM (LStmt GhcPs (LocatedA (body GhcPs))) checkLastStmt ctxt lstmt@(L loc stmt)@@ -2491,13 +2471,11 @@           BodyStmt _ e _ _ -> return (L loc (mkLastStmt e))           LastStmt {}      -> return lstmt   -- "Deriving" clauses may generate a                                              -- LastStmt directly (unlike the parser)-          _                -> do { addErr $ mkTcRnUnknownMessage-                                          $ mkPlainError noHints $-                                     (hang last_error 2 (ppr stmt))+          _                -> do { addErr $ TcRnLastStmtNotExpr ctxt+                                          $ UnexpectedStatement stmt                                  ; return lstmt }-    last_error = (text "The last statement in" <+> pprAStmtContext ctxt-                  <+> text "must be an expression") +     check_comp  -- Expect LastStmt; this should be enforced by the parser!       = case stmt of           LastStmt {} -> return lstmt@@ -2507,36 +2485,25 @@       = do { checkStmt ctxt lstmt; return lstmt }  -- Checking when a particular Stmt is ok-checkStmt :: HsStmtContext GhcRn+checkStmt :: AnnoBody body+          => HsStmtContext GhcRn           -> LStmt GhcPs (LocatedA (body GhcPs))           -> RnM () checkStmt ctxt (L _ stmt)   = do { dflags <- getDynFlags        ; case okStmt dflags ctxt stmt of-           IsValid        -> return ()-           NotValid extra -> addErr $ mkTcRnUnknownMessage-                                    $ mkPlainError noHints (msg $$ extra) }-  where-   msg = sep [ text "Unexpected" <+> pprStmtCat stmt <+> text "statement"-             , text "in" <+> pprAStmtContext ctxt ]--pprStmtCat :: Stmt (GhcPass a) body -> SDoc-pprStmtCat (TransStmt {})     = text "transform"-pprStmtCat (LastStmt {})      = text "return expression"-pprStmtCat (BodyStmt {})      = text "body"-pprStmtCat (BindStmt {})      = text "binding"-pprStmtCat (LetStmt {})       = text "let"-pprStmtCat (RecStmt {})       = text "rec"-pprStmtCat (ParStmt {})       = text "parallel"-pprStmtCat (ApplicativeStmt {}) = panic "pprStmtCat: ApplicativeStmt"+           IsValid      -> return ()+           NotValid ext -> addErr $+              TcRnUnexpectedStatementInContext+                ctxt (UnexpectedStatement stmt) ext }  -------------emptyInvalid :: Validity  -- Payload is the empty document-emptyInvalid = NotValid Outputable.empty+emptyInvalid :: Validity' (Maybe LangExt.Extension)+emptyInvalid = NotValid Nothing -- Invalid, and no extension to suggest  okStmt, okDoStmt, okCompStmt, okParStmt    :: DynFlags -> HsStmtContext GhcRn-   -> Stmt GhcPs (LocatedA (body GhcPs)) -> Validity+   -> Stmt GhcPs (LocatedA (body GhcPs)) -> Validity' (Maybe LangExt.Extension) -- Return Nothing if OK, (Just extra) if not ok -- The "extra" is an SDoc that is appended to a generic error message @@ -2550,7 +2517,7 @@  okDoFlavourStmt   :: DynFlags -> HsDoFlavour -> HsStmtContext GhcRn-  -> Stmt GhcPs (LocatedA (body GhcPs)) -> Validity+  -> Stmt GhcPs (LocatedA (body GhcPs)) -> Validity' (Maybe LangExt.Extension) okDoFlavourStmt dflags flavour ctxt stmt = case flavour of       DoExpr{}     -> okDoStmt   dflags ctxt stmt       MDoExpr{}    -> okDoStmt   dflags ctxt stmt@@ -2559,7 +2526,7 @@       MonadComp    -> okCompStmt dflags ctxt stmt  --------------okPatGuardStmt :: Stmt GhcPs (LocatedA (body GhcPs)) -> Validity+okPatGuardStmt :: Stmt GhcPs (LocatedA (body GhcPs)) -> Validity' (Maybe LangExt.Extension) okPatGuardStmt stmt   = case stmt of       BodyStmt {} -> IsValid@@ -2579,7 +2546,7 @@        RecStmt {}          | LangExt.RecursiveDo `xopt` dflags -> IsValid          | ArrowExpr <- ctxt -> IsValid    -- Arrows allows 'rec'-         | otherwise         -> NotValid (text "Use RecursiveDo")+         | otherwise         -> NotValid (Just LangExt.RecursiveDo)        BindStmt {} -> IsValid        LetStmt {}  -> IsValid        BodyStmt {} -> IsValid@@ -2593,10 +2560,10 @@        BodyStmt {} -> IsValid        ParStmt {}          | LangExt.ParallelListComp `xopt` dflags -> IsValid-         | otherwise -> NotValid (text "Use ParallelListComp")+         | otherwise -> NotValid (Just LangExt.ParallelListComp)        TransStmt {}          | LangExt.TransformListComp `xopt` dflags -> IsValid-         | otherwise -> NotValid (text "Use TransformListComp")+         | otherwise -> NotValid (Just LangExt.TransformListComp)        RecStmt {}  -> emptyInvalid        LastStmt {} -> emptyInvalid  -- Should not happen (dealt with by checkLastStmt)        ApplicativeStmt {} -> emptyInvalid@@ -2608,21 +2575,14 @@         ; checkErr (all tupArgPresent args || tuple_section) msg }   where     msg :: TcRnMessage-    msg = mkTcRnUnknownMessage $ mkPlainError noHints $-      text "Illegal tuple section: use TupleSections"+    msg = TcRnIllegalTupleSection  --------- sectionErr :: HsExpr GhcPs -> TcRnMessage-sectionErr expr-  = mkTcRnUnknownMessage $ mkPlainError noHints $-    hang (text "A section must be enclosed in parentheses")-       2 (text "thus:" <+> (parens (ppr expr)))+sectionErr = TcRnSectionWithoutParentheses -badIpBinds :: Outputable a => SDoc -> a -> TcRnMessage-badIpBinds what binds-  = mkTcRnUnknownMessage $ mkPlainError noHints $-    hang (text "Implicit-parameter bindings illegal in" <+> what)-         2 (ppr binds)+badIpBinds :: Either (HsLocalBindsLR GhcPs GhcPs) (HsLocalBindsLR GhcRn GhcPs) -> TcRnMessage+badIpBinds = TcRnIllegalImplicitParameterBindings  --------- @@ -2692,7 +2652,7 @@       | (isQualifiedDo || rebindableSyntax) && overloadedStrings = do         (failExpr, failFvs) <- lookupQualifiedDoExpr ctxt failMName         (fromStringExpr, fromStringFvs) <- lookupSyntaxExpr fromStringName-        let arg_lit = mkVarOcc "arg"+        let arg_lit = mkVarOccFS (fsLit "arg")         arg_name <- newSysName arg_lit         let arg_syn_expr = nlHsVar arg_name             body :: LHsExpr GhcRn =
compiler/GHC/Rename/Expr.hs-boot view
@@ -1,12 +1,6 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ConstraintKinds #-} module GHC.Rename.Expr where -#if MIN_VERSION_GLASGOW_HASKELL(9,3,0,0)-import Data.Type.Equality (type (~))-#endif- import GHC.Types.Name import GHC.Hs import GHC.Types.Name.Set ( FreeVars )@@ -21,10 +15,8 @@  type AnnoBody body   = ( Outputable (body GhcPs)-    , Anno (StmtLR GhcPs GhcPs (LocatedA (body GhcPs))) ~ SrcSpanAnnA-    , Anno (StmtLR GhcRn GhcPs (LocatedA (body GhcPs))) ~ SrcSpanAnnA-    , Anno (StmtLR GhcRn GhcRn (LocatedA (body GhcRn))) ~ SrcSpanAnnA     )+ rnStmts :: --forall thing body.            AnnoBody body => HsStmtContext GhcRn         -> (body GhcPs -> RnM (body GhcRn, FreeVars))
compiler/GHC/Rename/Module.hs view
@@ -4,7 +4,6 @@ {-# LANGUAGE TypeFamilies        #-}  {-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}-{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}  {- (c) The GRASP/AQUA Project, Glasgow University, 1992-1998@@ -2036,7 +2035,7 @@ {- Note [Type data declarations] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-With the TypeData extension (GHC proposal #106), one can write "type data"+With the TypeData extension (GHC proposal #106), one can write `type data` declarations, like      type data Nat = Zero | Succ Nat@@ -2047,17 +2046,18 @@         Zero :: Nat         Succ :: Nat -> Nat -This defines the constructors Zero and Succ in the TcCls namespace+This defines the constructors `Zero` and `Succ` in the TcCls namespace (type constructors and classes) instead of the Data namespace (data-constructors).  This contrasts with the DataKinds extension, which allows-constructors defined in the Data namespace to be promoted to the TcCls-namespace at the point of use in a type.+constructors).  This contrasts with the DataKinds extension, which+allows constructors defined in the Data namespace to be promoted to the+TcCls namespace at the point of use in a type. -Type data declarations have the syntax of data declarations, either-ordinary algebraic data types or GADTs, preceded by "type", with the-following restrictions:+Type data declarations have the syntax of `data` declarations (but not+`newtype` declarations), either ordinary algebraic data types or GADTs,+preceded by `type`, with the following restrictions: -(R1) There are data type contexts (even with the DatatypeContexts extension).+(R1) There are no data type contexts (even with the DatatypeContexts+     extension).  (R2) There are no labelled fields.  Perhaps these could be supported      using type families, but they are omitted for now.@@ -2078,14 +2078,15 @@  The main parts of the implementation are: -* The Bool argument to DataTypeCons (in Language.Haskell.Syntax.Decls)-  distinguishes "type data" declarations from ordinary "data" declarations.+* The parser recognizes `type data` (but not `type newtype`). -* This flag is set, and the constructor names placed in the-  TcCls namespace, during the initial construction of the AST in-  GHC.Parser.PostProcess.checkNewOrData.+* During the initial construction of the AST,+  GHC.Parser.PostProcess.checkNewOrData sets the `Bool` argument of the+  `DataTypeCons` inside a `HsDataDefn` to mark a `type data` declaration.+  It also puts the the constructor names (`Zero` and `Succ` in our+  example) in the TcCls namespace. -* GHC.Rename.Module.rnDataDefn calls check_type_data on these+* GHC.Rename.Module.rnDataDefn calls `check_type_data` on these   declarations, which checks that the TypeData extension is enabled and   checks restrictions (R1), (R2), (R3) and (R5).  They could equally   well be checked in the typechecker, but we err on the side of catching@@ -2094,19 +2095,40 @@ * GHC.Tc.TyCl.checkValidDataCon checks restriction (R4) on these declarations.  * When beginning to type check a mutually recursive group of declarations,-  the "type data" constructors are added to the type-checker environment-  as APromotionErr TyConPE by GHC.Tc.TyCl.mkPromotionErrorEnv, so they-  cannot be used within the recursive group.  This mirrors the DataKinds-  behaviour described at Note [Recursion and promoting data constructors]-  in GHC.Tc.TyCl.  For example, this is rejected:+  the `type data` constructors (`Zero` and `Succ` in our example) are+  added to the type-checker environment as `APromotionErr TyConPE` by+  GHC.Tc.TyCl.mkPromotionErrorEnv, so they cannot be used within the+  recursive group.  This mirrors the DataKinds behaviour described+  at Note [Recursion and promoting data constructors] in GHC.Tc.TyCl.+  For example, this is rejected: -    type data T f = K (f (K Int))+    type data T f = K (f (K Int)) -- illegal: tycon K is recursively defined -* After a "type data" declaration has been type-checked, the type-checker-  environment entry for each constructor (which can be recognized-  by being in the TcCls namespace) is just the promoted type-  constructor, not the bundle required for a data constructor.-  (GHC.Types.TyThing.implicitTyConThings)+* The `type data` data type, such as `Nat` in our example, is represented+  by a `TyCon` that is an `AlgTyCon`, but its `AlgTyConRhs` has the+  `is_type_data` field set.++* The constructors of the data type, `Zero` and `Succ` in our example,+  are each represented by a `DataCon` as usual.  That `DataCon`'s+  `dcPromotedField` is a `TyCon` (for `Zero`, say) that you can use+  in a type.++* After a `type data` declaration has been type-checked, the type-checker+  environment entry for each constructor (`Zero` and `Succ` in our+  example) is just the promoted type constructor, not the bundle required+  for a data constructor.  (GHC.Types.TyThing.implicitTyConThings)++* GHC.Core.TyCon.isDataKindsPromotedDataCon ignores promoted constructors+  from `type data`, which do not use the distinguishing quote mark added+  to constructors promoted by DataKinds.++* GHC.Core.TyCon.isDataTyCon ignores types coming from a `type data`+  declaration (by checking the `is_type_data` field), so that these do+  not contribute executable code such as constructor wrappers.++* The `is_type_data` field is copied into a Boolean argument+  of the `IfDataTyCon` constructor of `IfaceConDecls` by+  GHC.Iface.Make.tyConToIfaceDecl.  -} 
compiler/GHC/Rename/Names.hs view
@@ -11,9 +11,6 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE LambdaCase #-} -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}-{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}- module GHC.Rename.Names (         rnImports, getLocalNonValBinders, newRecordSelector,         extendGlobalRdrEnvRn,@@ -56,7 +53,6 @@ import GHC.Utils.Outputable as Outputable import GHC.Utils.Misc as Utils import GHC.Utils.Panic-import GHC.Utils.Trace  import GHC.Types.Fixity.Env import GHC.Types.SafeHaskell@@ -920,8 +916,15 @@           --    foreign decls and pattern synonyms for an ordinary module           --    type sigs in case of a hs-boot file only         ; is_boot <- tcIsHsBootOrSig-        ; let val_bndrs | is_boot   = hs_boot_sig_bndrs-                        | otherwise = for_hs_bndrs+        ; let val_bndrs+                | is_boot = case binds of+                      ValBinds _ _val_binds val_sigs ->+                          -- In a hs-boot file, the value binders come from the+                          --  *signatures*, and there should be no foreign binders+                          [ L (l2l decl_loc) (unLoc n)+                          | L decl_loc (TypeSig _ ns _) <- val_sigs, n <- ns]+                      _ -> panic "Non-ValBinds in hs-boot group"+                | otherwise = for_hs_bndrs         ; val_avails <- mapM new_simple val_bndrs          ; let avails    = concat nti_availss ++ val_avails@@ -942,15 +945,8 @@         ; traceRn "getLocalNonValBinders 3" (vcat [ppr flds, ppr field_env])         ; return (envs, new_bndrs) } }   where-    ValBinds _ _val_binds val_sigs = binds-     for_hs_bndrs :: [LocatedN RdrName]     for_hs_bndrs = hsForeignDeclsBinders foreign_decls--    -- In a hs-boot file, the value binders come from the-    --  *signatures*, and there should be no foreign binders-    hs_boot_sig_bndrs = [ L (l2l decl_loc) (unLoc n)-                        | L decl_loc (TypeSig _ ns _) <- val_sigs, n <- ns]        -- the SrcSpan attached to the input should be the span of the       -- declaration, not just the name
compiler/GHC/Rename/Pat.hs view
@@ -7,9 +7,6 @@ {-# LANGUAGE ViewPatterns        #-} {-# LANGUAGE DisambiguateRecordFields #-} -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}-{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}- {- (c) The GRASP/AQUA Project, Glasgow University, 1992-1998 @@ -78,6 +75,8 @@ import qualified GHC.LanguageExtensions as LangExt  import Control.Monad       ( when, ap, guard, unless )+import Data.Foldable+import Data.Functor.Identity ( Identity (..) ) import qualified Data.List.NonEmpty as NE import Data.Maybe import Data.Ratio@@ -405,9 +404,10 @@ --   * local namemaker --   * unused and duplicate checking --   * no fixities-rnPats :: HsMatchContext GhcRn -- for error messages-       -> [LPat GhcPs]-       -> ([LPat GhcRn] -> RnM (a, FreeVars))+rnPats :: Traversable f+       => HsMatchContext GhcRn -- for error messages+       -> f (LPat GhcPs)+       -> (f (LPat GhcRn) -> RnM (a, FreeVars))        -> RnM (a, FreeVars) rnPats ctxt pats thing_inside   = do  { envs_before <- getRdrEnvs@@ -424,7 +424,7 @@           --    complain *twice* about duplicates e.g. f (x,x) = ...           --           -- See Note [Don't report shadowing for pattern synonyms]-        ; let bndrs = collectPatsBinders CollNoDictBinders pats'+        ; let bndrs = collectPatsBinders CollNoDictBinders (toList pats')         ; addErrCtxt doc_pat $           if isPatSynCtxt ctxt              then checkDupNames bndrs@@ -432,6 +432,8 @@         ; thing_inside pats' } }   where     doc_pat = text "In" <+> pprMatchContext ctxt+{-# SPECIALIZE rnPats :: HsMatchContext GhcRn -> [LPat GhcPs] -> ([LPat GhcRn] -> RnM (a, FreeVars)) -> RnM (a, FreeVars) #-}+{-# SPECIALIZE rnPats :: HsMatchContext GhcRn -> Identity (LPat GhcPs) -> (Identity (LPat GhcRn) -> RnM (a, FreeVars)) -> RnM (a, FreeVars) #-}  rnPat :: HsMatchContext GhcRn -- for error messages       -> LPat GhcPs@@ -439,7 +441,7 @@       -> RnM (a, FreeVars)     -- Variables bound by pattern do not                                -- appear in the result FreeVars rnPat ctxt pat thing_inside-  = rnPats ctxt [pat] (\pats' -> let [pat'] = pats' in thing_inside pat')+  = rnPats ctxt (Identity pat) (thing_inside . runIdentity)  applyNameMaker :: NameMaker -> LocatedN RdrName -> RnM (LocatedN Name) applyNameMaker mk rdr = do { (n, _fvs) <- runCps (newPatLName mk rdr)@@ -471,7 +473,7 @@ -- ----------- Entry point 3: rnLPatAndThen ------------------- -- General version: parameterized by how you make new names -rnLPatsAndThen :: NameMaker -> [LPat GhcPs] -> CpsRn [LPat GhcRn]+rnLPatsAndThen :: Traversable f => NameMaker -> f (LPat GhcPs) -> CpsRn (f (LPat GhcRn)) rnLPatsAndThen mk = mapM (rnLPatAndThen mk)   -- Despite the map, the monad ensures that each pattern binds   -- variables that may be mentioned in subsequent patterns in the list@@ -963,7 +965,7 @@     , denominator val == 1 = HsIntegral (IL {il_text=src,il_neg=neg,il_value=numerator val}) generalizeOverLitVal lit = lit -isNegativeZeroOverLit :: HsOverLit t -> Bool+isNegativeZeroOverLit :: (XXOverLit t ~ DataConCantHappen) => HsOverLit t -> Bool isNegativeZeroOverLit lit  = case ol_val lit of         HsIntegral i    -> 0 == il_value i && il_neg i@@ -985,7 +987,7 @@ can apply it explicitly. In this case it stays negative zero.  #13211 -} -rnOverLit :: HsOverLit t ->+rnOverLit :: (XXOverLit t ~ DataConCantHappen) => HsOverLit t ->              RnM ((HsOverLit GhcRn, Maybe (HsExpr GhcRn)), FreeVars) rnOverLit origLit   = do  { opt_NumDecimals <- xoptM LangExt.NumDecimals
compiler/GHC/Rename/Splice.hs view
@@ -1,8 +1,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-} -{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}- module GHC.Rename.Splice (         rnTopSpliceDecls, @@ -33,7 +31,7 @@ import GHC.Rename.Module  ( rnSrcDecls, findSplice ) import GHC.Rename.Pat     ( rnPat ) import GHC.Types.Error-import GHC.Types.Basic    ( TopLevelFlag, isTopLevel )+import GHC.Types.Basic    ( TopLevelFlag, isTopLevel, maxPrec ) import GHC.Types.SourceText ( SourceText(..) ) import GHC.Utils.Outputable import GHC.Unit.Module@@ -673,22 +671,34 @@        = ( makePending UntypedTypeSplice name rn_splice          , HsSpliceTy (HsUntypedSpliceNested name) rn_splice) +    run_type_splice :: HsUntypedSplice GhcRn -> RnM (HsType GhcRn, FreeVars)     run_type_splice rn_splice       = do { traceRn "rnSpliceType: untyped type splice" empty            ; (hs_ty2, mod_finalizers) <-                 runRnSplice UntypedTypeSplice runMetaT ppr rn_splice            ; (hs_ty3, fvs) <- do { let doc = SpliceTypeCtx hs_ty2                                  ; checkNoErrs $ rnLHsType doc hs_ty2 }-                                    -- checkNoErrs: see Note [Renamer errors]+                                         -- checkNoErrs: see Note [Renamer errors]+              -- See Note [Delaying modFinalizers in untyped splices].-           ; return ( HsParTy noAnn-                              $ flip HsSpliceTy rn_splice-                              . HsUntypedSpliceTop (ThModFinalizers mod_finalizers)-                                  <$> hs_ty3+           ; return ( HsSpliceTy (HsUntypedSpliceTop (ThModFinalizers mod_finalizers)+                                                     (mb_paren hs_ty3))+                                 rn_splice                     , fvs                     ) }               -- Wrap the result of the splice in parens so that we don't               -- lose the outermost location set by runQuasiQuote (#7918)++    -- Wrap a non-atomic result in HsParTy parens;+    -- but not if it's atomic to avoid double parens for operators+    -- This is to account for, say  foo :: $(blah) -> Int+    -- when we want $(blah) to expand to (this -> that), with parens.+    -- Sadly, it's awkward add precisely the correct parens, because+    -- that depends on the context.+    mb_paren :: LHsType GhcRn -> LHsType GhcRn+    mb_paren lhs_ty@(L loc hs_ty)+      | hsTypeNeedsParens maxPrec hs_ty = L loc (HsParTy noAnn lhs_ty)+      | otherwise                       = lhs_ty  {- Note [Partial Type Splices] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compiler/GHC/Rename/Utils.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies     #-}+{-# LANGUAGE GADTs            #-} -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} {-  This module contains miscellaneous functions related to renaming.
compiler/GHC/Runtime/Debugger.hs view
@@ -97,8 +97,8 @@    printSDocs :: GhcMonad m => [SDoc] -> m ()    printSDocs sdocs = do       logger <- getLogger-      unqual <- GHC.getPrintUnqual-      liftIO $ printOutputForUser logger unqual $ vcat sdocs+      name_ppr_ctx <- GHC.getNamePprCtx+      liftIO $ printOutputForUser logger name_ppr_ctx $ vcat sdocs     -- Do the obtainTerm--bindSuspensions-computeSubstitution dance    go :: GhcMonad m => Subst -> Id -> m (Subst, Term)
compiler/GHC/Runtime/Eval.hs view
@@ -72,6 +72,7 @@ import GHC.Core.FVs        ( orphNamesOfFamInst ) import GHC.Core.TyCon import GHC.Core.Type       hiding( typeKind )+import GHC.Core.TyCo.Ppr import qualified GHC.Core.Type as Type  import GHC.Iface.Env       ( newInteractiveBinder )@@ -91,7 +92,6 @@ import GHC.Utils.Outputable import GHC.Utils.Misc import GHC.Utils.Logger-import GHC.Utils.Trace  import GHC.Types.RepType import GHC.Types.Fixity.Env@@ -669,9 +669,12 @@              Nothing -> return hsc_env              Just new_ty -> do               case improveRTTIType hsc_env old_ty new_ty of-               Nothing -> return $-                        warnPprTrace True (":print failed to calculate the "-                                           ++ "improvement for a type") empty hsc_env+               Nothing -> warnPprTrace True (":print failed to calculate the "+                                             ++ "improvement for a type")+                              (vcat [ text "id" <+> ppr id+                                    , text "old_ty" <+> debugPprType old_ty+                                    , text "new_ty" <+> debugPprType new_ty ]) $+                          return hsc_env                Just subst -> do                  let logger = hsc_logger hsc_env                  putDumpFileMaybe logger Opt_D_dump_rtti "RTTI"@@ -1049,7 +1052,7 @@ -- Get all the constraints required of a dictionary binding getDictionaryBindings :: PredType -> TcM CtEvidence getDictionaryBindings theta = do-  dictName <- newName (mkDictOcc (mkVarOcc "magic"))+  dictName <- newName (mkDictOcc (mkVarOccFS (fsLit "magic")))   let dict_var = mkVanillaGlobal dictName theta   loc <- getCtLocM (GivenOrigin (getSkolemInfo unkSkol)) Nothing @@ -1072,8 +1075,8 @@     k -> Constraint where k is the type of the queried type.   -}   try_cls ies cls-    | Just (_, arg_kind, res_kind) <- splitFunTy_maybe (tyConKind $ classTyCon cls)-    , tcIsConstraintKind res_kind+    | Just (_, _, arg_kind, res_kind) <- splitFunTy_maybe (tyConKind $ classTyCon cls)+    , isConstraintKind res_kind     , Type.typeKind ty `eqType` arg_kind     , (matches, _, _) <- lookupInstEnv True ies cls [ty]     = matches
compiler/GHC/Runtime/Heap/Inspect.hs view
@@ -36,7 +36,8 @@ import GHC.Types.RepType import GHC.Core.Multiplicity import qualified GHC.Core.Unify as U-import GHC.Types.Var+import GHC.Core.TyCon+ import GHC.Tc.Utils.Monad import GHC.Tc.Utils.TcType import GHC.Tc.Utils.TcMType@@ -44,7 +45,7 @@ import GHC.Tc.Utils.Unify import GHC.Tc.Utils.Env -import GHC.Core.TyCon+import GHC.Types.Var import GHC.Types.Name import GHC.Types.Name.Occurrence as OccName import GHC.Unit.Module@@ -675,7 +676,7 @@   where     do_pair (tc_tv, rtti_tv)       = do { tc_ty <- zonkTcTyVar tc_tv-           ; case tcGetTyVar_maybe tc_ty of+           ; case getTyVar_maybe tc_ty of                Just tv | isMetaTyVar tv -> writeMetaTyVar tv (mkTyVarTy rtti_tv)                _                        -> return () } @@ -748,10 +749,13 @@                       -- we have unsound types. Replace constructor types in                       -- subterms with tyvars                       zterm' <- mapTermTypeM-                                 (\ty -> case tcSplitTyConApp_maybe ty of-                                           Just (tc, _:_) | tc /= funTyCon-                                               -> newOpenVar-                                           _   -> return ty)+                                 (\ty -> case splitTyConApp_maybe ty of+                                           -- SPJ: I have no idea why we are+                                           --      matching on (:) here, nor+                                           --      what the isFunTy is for+                                           Just (_tc, _ : _) | not (isFunTy ty)+                                                             -> newOpenVar+                                           _ -> return ty)                                  term                       zonkTerm zterm'    traceTR (text "Term reconstruction completed." $$@@ -1346,12 +1350,13 @@                           ppr tv, equals, ppr ty_v]          go ty_v r -- FunTy inductive case-    | Just (w1,l1,l2) <- splitFunTy_maybe l-    , Just (w2,r1,r2) <- splitFunTy_maybe r+    | Just (af1,w1,l1,l2) <- splitFunTy_maybe l+    , Just (af2,w2,r1,r2) <- splitFunTy_maybe r+    , af1==af2     , w1 `eqType` w2     = do r2' <- go l2 r2          r1' <- go l1 r1-         return (mkVisFunTy w1 r1' r2')+         return (mkFunTy af1 w1 r1' r2') -- TyconApp Inductive case; this is the interesting bit.     | Just (tycon_l, _) <- tcSplitTyConApp_maybe lhs     , Just (tycon_r, _) <- tcSplitTyConApp_maybe rhs@@ -1416,7 +1421,7 @@   , concrete_args <- [ arg | (tyv,arg) <- tyConTyVars tc `zip` all_args                            , tyv `notElem` phantom_vars]   = all isMonomorphicOnNonPhantomArgs concrete_args-  | Just (_, ty1, ty2) <- splitFunTy_maybe ty+  | Just (_, _, ty1, ty2) <- splitFunTy_maybe ty   = all isMonomorphicOnNonPhantomArgs [ty1,ty2]   | otherwise = isMonomorphic ty 
compiler/GHC/Runtime/Loader.hs view
@@ -21,6 +21,7 @@     ) where  import GHC.Prelude+import GHC.Data.FastString  import GHC.Driver.Session import GHC.Driver.Ppr@@ -38,15 +39,16 @@ import GHC.Builtin.Names ( pluginTyConName, frontendPluginTyConName )  import GHC.Driver.Env-import GHCi.RemoteTypes  ( HValue )-import GHC.Core.Type     ( Type, eqType, mkTyConTy )-import GHC.Core.TyCon    ( TyCon )+import GHCi.RemoteTypes     ( HValue )+import GHC.Core.Type        ( Type, mkTyConTy )+import GHC.Core.TyCo.Compare( eqType )+import GHC.Core.TyCon       ( TyCon )  import GHC.Types.SrcLoc        ( noSrcSpan ) import GHC.Types.Name    ( Name, nameModule_maybe ) import GHC.Types.Id      ( idType ) import GHC.Types.TyThing-import GHC.Types.Name.Occurrence ( OccName, mkVarOcc )+import GHC.Types.Name.Occurrence ( OccName, mkVarOccFS ) import GHC.Types.Name.Reader   ( RdrName, ImportSpec(..), ImpDeclSpec(..)                                , ImpItemSpec(..), mkGlobalRdrEnv, lookupGRE_RdrName                                , greMangledName, mkRdrQual )@@ -136,14 +138,14 @@       where         options = [ option | (opt_mod_nm, option) <- pluginModNameOpts dflags                             , opt_mod_nm == mod_nm ]-    loadPlugin = loadPlugin' (mkVarOcc "plugin") pluginTyConName hsc_env+    loadPlugin = loadPlugin' (mkVarOccFS (fsLit "plugin")) pluginTyConName hsc_env   loadFrontendPlugin :: HscEnv -> ModuleName -> IO (FrontendPlugin, [Linkable], PkgsLoaded) loadFrontendPlugin hsc_env mod_name = do     checkExternalInterpreter hsc_env     (plugin, _iface, links, pkgs)-      <- loadPlugin' (mkVarOcc "frontendPlugin") frontendPluginTyConName+      <- loadPlugin' (mkVarOccFS (fsLit "frontendPlugin")) frontendPluginTyConName            hsc_env mod_name     return (plugin, links, pkgs) 
compiler/GHC/Stg/BcPrep.hs view
@@ -144,7 +144,7 @@ newId :: Type -> BcPrepM Id newId ty = do     uniq <- newUnique-    return $ mkSysLocal prepFS uniq Many ty+    return $ mkSysLocal prepFS uniq ManyTy ty  prepFS :: FastString prepFS = fsLit "bcprep"
compiler/GHC/Stg/InferTags/Rewrite.hs view
@@ -52,9 +52,6 @@  import Control.Monad --- import GHC.Utils.Trace--- import GHC.Driver.Ppr- newtype RM a = RM { unRM :: (State (UniqFM Id TagSig, UniqSupply, Module, IdSet) a) }     deriving (Functor, Monad, Applicative) 
compiler/GHC/Stg/Lift/Analysis.hs view
@@ -326,7 +326,7 @@ rhsCard :: Id -> Card rhsCard bndr   | is_thunk  = oneifyCard n-  | otherwise = n `multCard` peelManyCalls (idArity bndr) cd+  | otherwise = n `multCard` (fst $ peelManyCalls (idArity bndr) cd)   where     is_thunk = idArity bndr == 0     -- Let's pray idDemandInfo is still OK after unarise...
compiler/GHC/Stg/Lift/Monad.hs view
@@ -282,7 +282,7 @@         -- See Note [transferPolyIdInfo] in GHC.Types.Id. We need to do this at least         -- for arity information.         = transferPolyIdInfo bndr (dVarSetElems abs_ids)-        . mkSysLocal str uniq Many+        . mkSysLocal str uniq ManyTy         $ ty   LiftM $ RWS.local     (\e -> e
compiler/GHC/Stg/Subst.hs view
@@ -11,7 +11,13 @@ import GHC.Utils.Outputable import GHC.Utils.Misc import GHC.Utils.Panic-import GHC.Utils.Trace++-- TODO: This code might make folly of the work done in CorePrep where+-- we clone local ids in order to ensure *all* local binders are unique.+-- It's my understanding that here we use "the rapier"/uniqAway which makes up+-- uniques based on the ids in scope. Which can give the same unique to different+-- binders as long as they are in different scopes. A guarantee which isn't+-- strong enough for code generation in general. See Note [CorePrep Overview].  -- | A renaming substitution from 'Id's to 'Id's. Like 'RnEnv2', but not -- maintaining pairs of substitutions. Like 'GHC.Core.Subst.Subst', but
compiler/GHC/Stg/Unarise.hs view
@@ -2,8 +2,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TupleSections    #-} -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}- {- (c) The GRASP/AQUA Project, Glasgow University, 1992-2012 @@ -186,6 +184,129 @@ layout to use. Note that unlifted values can't be let-bound, so we don't need types in StgRhsCon. +Note [Casting slot arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this function which selects between Int32# and Int64# from a unboxed sum.++    foo ::  (# Int32# | Int64#  #) -> FD+    foo x = case x of+        (# x1 | #) -> F x1+        (# | x2 #) -> D x2++Naturally we would expect x1 to have a PrimRep of Int32Rep and x2 of DoubleRep.+However we used to generate this (bogus) code after Unarise giving rise to #22208:++    M.foo :: (# GHC.Prim.Int32# | GHC.Prim.Int64# #) -> M.FD+    [GblId, Arity=1, Unf=OtherCon []] =+        {} \r [sum_tag sum_field]+            case sum_tag of tag_gsc {+              __DEFAULT -> M.F [sum_field];+              2# -> M.D [sum_field];+            };++Where sum_field is used both as Int32# and Int64# depending on the branch+because they share the same SlotTy.+This usually works out since we put all int's in the same sort of register.+So even if the reps where wrong (x :: bits32) = (y :: bits64) would produce+correct code in the most cases.+However there are cases where this goes wrong, causing lint errors,in the case of #22208+compiler panics or in some cases incorrect results in the C backend.+For now our solution is to construct proper casts between the PrimRep of the slot and+the variables we want to store in, or read out of these slots.++This means when we have a sum (# Int32# | Int64# #) if we want to store a Int32+we convert it to a Int64 on construction of the tuple value, and convert it back+to a Int32 once when want to use the field. On most backends these coversions should+be no-ops at runtime so this seems reasonable.++Conversion for values coming out of a strict field happen in mapSumIdBinders. While+conversion during the construction of sums happen inside mkUbxSum.++------------- A full example of casting during sum construction ----------------++To compile a constructor application of a unboxed sum of type (# Int32# | Int64# )+in an expression like  `let sum = (# x | #)` we will call mkUbxSum to determine+which binders we have to replace sum with at use sites during unarise.+See also Note [Translating unboxed sums to unboxed tuples].++Int32# and Int64# in this case will share the same slot in the unboxed sum. This means+the sum after unarise will be represented by two binders. One for the tag and one for+the field. The later having Int64Rep.+However our input for the field is of Int32Rep. So in order to soundly construct+`(# x | #) :: (# Int32# | Int64# )` we must upcast `x` to Int64#.+To do this mkUbxSum will produce an expression with a hole for constructor application+to go into. That is the call to mkUbxSum and it's result will look something like:++  >>> mkUbxSum (#|#) [Int32#, Int64#] (x::Int32#) us (x')+  ([1#::Int#, x'::Int64#], \rhs -> case int32ToInt# x of x' -> rhs )++We will use the returned arguments to construct an application to an unboxed tuple:++  >>> mkTuple [tag::Int#, x'::Int64#]+  (# tag, x' #)++Which we will then use as the rhs to pass into the casting wrapper to+construct an expression that casts `x` to the right type before constructing the+tuple++  >>> (\rhs -> case int32ToInt# x of x' -> rhs ) (# tag, x' #)+  case int32ToInt# x of x' -> (# #) 1# x'++Which results in the this definition for `sum` after all is said and done:++  let sum = case int32ToInt# x of { x' -> (# #) 1# x' }++Not that the renaming is not optional. Cmm requires binders of different uniques+to have at least different types. See Note [CorePrep Overview]: 6. Clone all local Ids++------------- A full example of casting during sum matching --------------------++When matching on an unboxed sum constructor we start out with+something like this the pre-unarise:++    f :: (# Int32 | Int64# ) -> ...+    f sum = case sum of+        (# x |#) -> alt_rhs+        ...++We unarise the function arguments and get:++    f sum_tag sum_slot1 = case sum_tag of+        1# -> ???++Now we need to match up the original alternative binders with the sum slots passed+to the function. This is done by mapSumIdBinders which we we call for our+example alternative like this:++    >>> mapSumIdBinders [x] [sum_slot1] alt_rhs env+    (env', alt_rhs')++mapSumIdBinders first matches up the list of binders with the slots passed to+the function which is trivial in this case. Then we check if the slot and the+variable residing inside it agree on their Rep. If alternative binders and+the function arguments agree in their slot reps we we just extend the environment+with a mapping from `x` to `sum_slot1` and we return the rhs as is.++If the reps of the sum_slots do not agree with alternative binders they represent+then we need to wrap the whole RHS in nested cases which cast the sum_slot<n>+variables to the correct rep. Here `x` is of Int32Rep while `sum_slot1` will be+of Int64Rep. This means instead of retuning the original alt_rhs we will return:++  >>> mapSumIdBinders [x] [sum_slot1] alt_rhs env+  ( env'[x=x']+  , case int64ToInt32# (sum_slot1 :: Int64#) of+      (x' :: Int32#) -> alt_rhs+  )++We then run unarise on alt_rhs within that expression, which will replace the first occurence+of `x` with sum_slot_arg_1 giving us post-unarise:++    f sum_tag sum_slot1 =+      case sum_tag of+        1# -> case int64ToInt32# sum_slot1 of+          x' -> ... x' ...+        ...+ Note [UnariseEnv] ~~~~~~~~~~~~~~~~~~ At any variable occurrence 'v',@@ -258,8 +379,8 @@ import GHC.Types.Basic import GHC.Core import GHC.Core.DataCon-import GHC.Core.TyCon ( isVoidRep )-import GHC.Data.FastString (FastString, mkFastString)+import GHC.Core.TyCon+import GHC.Data.FastString (FastString, mkFastString, fsLit) import GHC.Types.Id import GHC.Types.Literal import GHC.Core.Make (aBSENT_SUM_FIELD_ERROR_ID)@@ -275,13 +396,19 @@ import GHC.Builtin.Types.Prim (intPrimTy) import GHC.Builtin.Types import GHC.Types.Unique.Supply+import GHC.Types.Unique import GHC.Utils.Misc import GHC.Types.Var.Env  import Data.Bifunctor (second)+import Data.List.NonEmpty (NonEmpty (..)) import Data.Maybe (mapMaybe) import qualified Data.IntMap as IM+import GHC.Builtin.PrimOps+import GHC.Builtin.PrimOps.Casts+import Data.List (mapAccumL) +-- import GHC.Utils.Trace --------------------------------------------------------------------------------  -- | A mapping from binders to the Ids they were expanded/renamed to.@@ -306,8 +433,10 @@ -- INVARIANT: OutStgArgs in the range only have NvUnaryTypes --            (i.e. no unboxed tuples, sums or voids) ---type UnariseEnv = VarEnv UnariseVal+newtype UnariseEnv = UnariseEnv  { ue_rho :: (VarEnv UnariseVal) } +initUnariseEnv :: VarEnv UnariseVal -> UnariseEnv+initUnariseEnv = UnariseEnv data UnariseVal   = MultiVal [OutStgArg] -- MultiVal to tuple. Can be empty list (void).   | UnaryVal OutStgArg   -- See Note [Renaming during unarisation].@@ -320,25 +449,27 @@ -- The id is mapped to one or more things. -- See Note [UnariseEnv] extendRho :: UnariseEnv -> Id -> UnariseVal -> UnariseEnv-extendRho rho x (MultiVal args)+extendRho env x (MultiVal args)   = assert (all (isNvUnaryType . stgArgType) args)-    extendVarEnv rho x (MultiVal args)-extendRho rho x (UnaryVal val)+    env { ue_rho = extendVarEnv (ue_rho env) x (MultiVal args) }+extendRho env x (UnaryVal val)   = assert (isNvUnaryType (stgArgType val))-    extendVarEnv rho x (UnaryVal val)+    env { ue_rho = extendVarEnv (ue_rho env) x (UnaryVal val) } -- Properly shadow things from an outer scope. -- See Note [UnariseEnv]  -- The id stands for itself so we don't record a mapping. -- See Note [UnariseEnv] extendRhoWithoutValue :: UnariseEnv -> Id -> UnariseEnv-extendRhoWithoutValue rho x = delVarEnv rho x+extendRhoWithoutValue env x = env { ue_rho = delVarEnv (ue_rho env) x } +lookupRho :: UnariseEnv -> Id -> Maybe UnariseVal+lookupRho env v = lookupVarEnv (ue_rho env) v  --------------------------------------------------------------------------------  unarise :: UniqSupply -> [StgTopBinding] -> [StgTopBinding]-unarise us binds = initUs_ us (mapM (unariseTopBinding emptyVarEnv) binds)+unarise us binds = initUs_ us (mapM (unariseTopBinding (initUnariseEnv emptyVarEnv)) binds)  unariseTopBinding :: UnariseEnv -> StgTopBinding -> UniqSM StgTopBinding unariseTopBinding rho (StgTopLifted bind)@@ -366,7 +497,7 @@ unariseExpr :: UnariseEnv -> StgExpr -> UniqSM StgExpr  unariseExpr rho e@(StgApp f [])-  = case lookupVarEnv rho f of+  = case lookupRho rho f of       Just (MultiVal args)  -- Including empty tuples         -> return (mkTuple args)       Just (UnaryVal (StgVarArg f'))@@ -379,7 +510,7 @@ unariseExpr rho e@(StgApp f args)   = return (StgApp f' (unariseFunArgs rho args))   where-    f' = case lookupVarEnv rho f of+    f' = case lookupRho rho f of            Just (UnaryVal (StgVarArg f')) -> f'            Nothing -> f            err -> pprPanic "unariseExpr - app2" (pprStgExpr panicStgPprOpts e $$ ppr err)@@ -390,12 +521,17 @@   = return (StgLit l)  unariseExpr rho (StgConApp dc n args ty_args)-  | Just args' <- unariseMulti_maybe rho dc args ty_args-  = return (mkTuple args')--  | otherwise-  , let args' = unariseConArgs rho args-  = return (StgConApp dc n args' (map stgArgType args'))+  | isUnboxedSumDataCon dc || isUnboxedTupleDataCon dc+  = do+      us <- getUniqueSupplyM+      case unariseUbxSumOrTupleArgs rho us dc args ty_args of+        (args', Just cast_wrapper)+          -> return $ cast_wrapper (mkTuple args')+        (args', Nothing)+          -> return $ (mkTuple args')+  | otherwise =+      let args' = unariseConArgs rho args in+      return $ (StgConApp dc n args' (map stgArgType args'))  unariseExpr rho (StgOpApp op args ty)   = return (StgOpApp op (unariseFunArgs rho args) ty)@@ -403,15 +539,19 @@ unariseExpr rho (StgCase scrut bndr alt_ty alts)   -- tuple/sum binders in the scrutinee can always be eliminated   | StgApp v [] <- scrut-  , Just (MultiVal xs) <- lookupVarEnv rho v+  , Just (MultiVal xs) <- lookupRho rho v   = elimCase rho xs bndr alt_ty alts    -- Handle strict lets for tuples and sums:   --   case (# a,b #) of r -> rhs   -- and analogously for sums   | StgConApp dc _n args ty_args <- scrut-  , Just args' <- unariseMulti_maybe rho dc args ty_args-  = elimCase rho args' bndr alt_ty alts+  , isUnboxedSumDataCon dc || isUnboxedTupleDataCon dc+  = do+    us <- getUniqueSupplyM+    case unariseUbxSumOrTupleArgs rho us dc args ty_args of+      (args',Just wrapper) -> wrapper <$> elimCase rho args' bndr alt_ty alts+      (args',Nothing) -> elimCase rho args' bndr alt_ty alts    -- See (3) of Note [Rubbish literals] in GHC.Types.Literal   | StgLit lit <- scrut@@ -436,27 +576,31 @@   = StgTick tick <$> unariseExpr rho e  -- Doesn't return void args.-unariseMulti_maybe :: UnariseEnv -> DataCon -> [InStgArg] -> [Type] -> Maybe [OutStgArg]-unariseMulti_maybe rho dc args ty_args+unariseUbxSumOrTupleArgs :: UnariseEnv -> UniqSupply -> DataCon -> [InStgArg] -> [Type]+                   -> ( [OutStgArg]           -- Arguments representing the unboxed sum+                      , Maybe (StgExpr -> StgExpr)) -- Transformation to apply to the arguments, to bring them+                                                    -- into the right Rep+unariseUbxSumOrTupleArgs rho us dc args ty_args   | isUnboxedTupleDataCon dc-  = Just (unariseConArgs rho args)+  = (unariseConArgs rho args, Nothing)    | isUnboxedSumDataCon dc   , let args1 = assert (isSingleton args) (unariseConArgs rho args)-  = Just (mkUbxSum dc ty_args args1)+  = let (args2, cast_wrapper) = mkUbxSum dc ty_args args1 us+    in (args2, Just cast_wrapper)    | otherwise-  = Nothing+  = panic "unariseUbxSumOrTupleArgs: Constructor not a unboxed sum or tuple"  -- Doesn't return void args. unariseRubbish_maybe :: Literal -> Maybe [OutStgArg]-unariseRubbish_maybe (LitRubbish rep)+unariseRubbish_maybe (LitRubbish torc rep)   | [prep] <- preps   , not (isVoidRep prep)   = Nothing   -- Single, non-void PrimRep. Nothing to do!    | otherwise -- Multiple reps, possibly with VoidRep. Eliminate via elimCase-  = Just [ StgLitArg (LitRubbish (primRepToRuntimeRep prep))+  = Just [ StgLitArg (LitRubbish torc (primRepToRuntimeRep prep))          | prep <- preps, not (isVoidRep prep) ]   where     preps = runtimeRepPrimRep (text "unariseRubbish_maybe") rep@@ -473,20 +617,23 @@                                                  , alt_bndrs = bndrs                                                  , alt_rhs   = rhs}]   = do let rho1 = extendRho rho bndr (MultiVal args)-           rho2+       (rho2, rhs') <- case () of+           _              | isUnboxedTupleBndr bndr-             = mapTupleIdBinders bndrs args rho1+             -> return (mapTupleIdBinders bndrs args rho1, rhs)              | otherwise-             = assert (isUnboxedSumBndr bndr) $-               if null bndrs then rho1-                             else mapSumIdBinders bndrs args rho1+             -> assert (isUnboxedSumBndr bndr) $+               case bndrs of+                -- Sum with a void-type binder?+                [] -> return (rho1, rhs)+                [alt_bndr] -> mapSumIdBinders alt_bndr args rhs rho1+                _ -> pprPanic "mapSumIdBinders" (ppr bndrs $$ ppr args) -       unariseExpr rho2 rhs+       unariseExpr rho2 rhs' -elimCase rho args bndr (MultiValAlt _) alts+elimCase rho args@(tag_arg : real_args) bndr (MultiValAlt _) alts   | isUnboxedSumBndr bndr-  = do let (tag_arg : real_args) = args-       tag_bndr <- mkId (mkFastString "tag") tagTy+  = do tag_bndr <- mkId (mkFastString "tag") tagTy           -- this won't be used but we need a binder anyway        let rho1 = extendRho rho bndr (MultiVal args)            scrut' = case tag_arg of@@ -572,18 +719,23 @@ unariseSumAlt rho _ GenStgAlt{alt_con=DEFAULT,alt_bndrs=_,alt_rhs=e}   = GenStgAlt DEFAULT mempty <$> unariseExpr rho e -unariseSumAlt rho args GenStgAlt{ alt_con   = DataAlt sumCon+unariseSumAlt rho args alt@GenStgAlt{ alt_con   = DataAlt sumCon                                 , alt_bndrs = bs                                 , alt_rhs   = e                                 }-  = do let rho'     = mapSumIdBinders bs args rho-           lit_case = LitAlt (LitNumber LitNumInt (fromIntegral (dataConTag sumCon)))-       GenStgAlt lit_case mempty <$> unariseExpr rho' e +  = do (rho',e') <- case bs of+              [b] -> mapSumIdBinders b args e rho+              -- Sums must have one binder+              _ -> pprPanic "unariseSumAlt2" (ppr args $$ pprPanicAlt alt)+       let lit_case   = LitAlt (LitNumber LitNumInt (fromIntegral (dataConTag sumCon)))+       GenStgAlt lit_case mempty <$> unariseExpr rho' e'+ unariseSumAlt _ scrt alt-  = pprPanic "unariseSumAlt" (ppr scrt $$ pprPanicAlt alt)+  = pprPanic "unariseSumAlt3" (ppr scrt $$ pprPanicAlt alt)  --------------------------------------------------------------------------------+-- Mapping binders when matching und a unboxed sum/tuple  mapTupleIdBinders   :: [InId]       -- Un-processed binders of a tuple alternative.@@ -619,28 +771,91 @@       map_ids rho0 ids_unarised args0  mapSumIdBinders-  :: [InId]      -- Binder of a sum alternative (remember that sum patterns-                 -- only have one binder, so this list should be a singleton)+  :: InId        -- Binder (in the case alternative).   -> [OutStgArg] -- Arguments that form the sum (NOT including the tag).                  -- Can't have void args.-  -> UnariseEnv+  -> InStgExpr   -> UnariseEnv+  -> UniqSM (UnariseEnv, OutStgExpr) -mapSumIdBinders [id] args rho0-  = assert (not (any (isZeroBitTy . stgArgType) args)) $+mapSumIdBinders alt_bndr args rhs rho0+  = assert (not (any (isZeroBitTy . stgArgType) args)) $ do+    uss <- listSplitUniqSupply <$> getUniqueSupplyM     let+      fld_reps = typePrimRep (idType alt_bndr)++      -- Slots representing the whole sum       arg_slots = map primRepSlot $ concatMap (typePrimRep . stgArgType) args-      id_slots  = map primRepSlot $ typePrimRep (idType id)+      -- The slots representing the field of the sum we bind.+      id_slots  = map primRepSlot $ fld_reps       layout1   = layoutUbxSum arg_slots id_slots-    in-      if isMultiValBndr id-        then extendRho rho0 id (MultiVal [ args !! i | i <- layout1 ])-        else assert (layout1 `lengthIs` 1)-             extendRho rho0 id (UnaryVal (args !! head layout1)) -mapSumIdBinders ids sum_args _-  = pprPanic "mapSumIdBinders" (ppr ids $$ ppr sum_args)+      -- See Note [Casting slot arguments]+      -- Most of the code here is just to make sure our binders are of the+      -- right type.+      -- Select only the args which contain parts of the current field.+      id_arg_exprs   = [ args !! i | i <- layout1 ]+      id_vars   = [v | StgVarArg v <- id_arg_exprs]+      -- Output types for the field binders based on their rep+      id_tys    = map primRepToType fld_reps +      typed_id_arg_input = assert (equalLength id_vars id_tys) $+                           zip3 id_vars id_tys uss++      mkCastInput :: (Id,Type,UniqSupply) -> ([(PrimOp,Type,Unique)],Id,Id)+      mkCastInput (id,tar_type,bndr_us) =+        let (ops,types) = unzip $ getCasts (typePrimRep1 $ idType id) (typePrimRep1 tar_type)+            cst_opts = zip3 ops types $ uniqsFromSupply bndr_us+            out_id = case cst_opts of+              [] -> id+              _ ->  let (_,ty,uq) = last cst_opts+                    in mkCastVar uq ty+        in (cst_opts,id,out_id)++      cast_inputs = map mkCastInput typed_id_arg_input+      (rhs_with_casts,typed_ids) = mapAccumL cast_arg (\x->x) cast_inputs+        where+          cast_arg rhs_in (cast_ops,in_id,out_id) =+            let rhs_out = castArgRename cast_ops (StgVarArg in_id)+            in (rhs_in . rhs_out, out_id)++      typed_id_args = map StgVarArg typed_ids++      -- pprTrace "mapSumIdBinders"+      --           (text "id_tys" <+> ppr id_tys $$+      --           text "id_args" <+> ppr id_arg_exprs $$+      --           text "rhs" <+> ppr rhs $$+      --           text "rhs_with_casts" <+> ppr rhs_with_casts+      --           ) $+    if isMultiValBndr alt_bndr+      then return (extendRho rho0 alt_bndr (MultiVal typed_id_args), rhs_with_casts rhs)+      else assert (typed_id_args `lengthIs` 1) $+            return (extendRho rho0 alt_bndr (UnaryVal (head typed_id_args)), rhs_with_casts rhs)++-- Convert the argument to the given type, and wrap the conversion+-- around the given expression. Use the given Id as a name for the+-- converted value.+castArgRename :: [(PrimOp,Type,Unique)] -> StgArg -> StgExpr -> StgExpr+castArgRename ops in_arg rhs =+  case ops of+    [] -> rhs+    ((op,ty,uq):rest_ops) ->+      let out_id' = mkCastVar uq ty -- out_name `setIdUnique` uq `setIdType` ty+          sub_cast = castArgRename rest_ops (StgVarArg out_id')+      in mkCast in_arg op out_id' ty $ sub_cast rhs++-- Construct a case binder used when casting sums, of a given type and unique.+mkCastVar :: Unique -> Type -> Id+mkCastVar uq ty = mkSysLocal (fsLit "cst_sum") uq ManyTy ty++mkCast :: StgArg -> PrimOp -> OutId -> Type -> StgExpr -> StgExpr+mkCast arg_in cast_op out_id out_ty in_rhs =+  let r2 = typePrimRep1 out_ty+      scrut = StgOpApp (StgPrimOp cast_op) [arg_in] out_ty+      alt = GenStgAlt { alt_con = DEFAULT, alt_bndrs = [], alt_rhs = in_rhs}+      alt_ty = PrimAlt r2+  in (StgCase scrut out_id alt_ty [alt])+ -- | Build a unboxed sum term from arguments of an alternative. -- -- Example, for (# x | #) :: (# (# #) | Int #) we call@@ -652,31 +867,72 @@ --   [ 1#, rubbish ] -- mkUbxSum-  :: DataCon      -- Sum data con+  :: HasDebugCallStack+  => DataCon      -- Sum data con   -> [Type]       -- Type arguments of the sum data con   -> [OutStgArg]  -- Actual arguments of the alternative.-  -> [OutStgArg]  -- Final tuple arguments-mkUbxSum dc ty_args args0+  -> UniqSupply+  -> ([OutStgArg] -- Final tuple arguments+     ,(StgExpr->StgExpr) -- We might need to cast the args first+     )+mkUbxSum dc ty_args args0 us   = let-      (_ : sum_slots) = ubxSumRepType (map typePrimRep ty_args)-        -- drop tag slot-+      _ :| sum_slots = ubxSumRepType (map typePrimRep ty_args)+      -- drop tag slot+      field_slots = (mapMaybe (typeSlotTy . stgArgType) args0)       tag = dataConTag dc+      layout'  = layoutUbxSum sum_slots field_slots -      layout'  = layoutUbxSum sum_slots (mapMaybe (typeSlotTy . stgArgType) args0)       tag_arg  = StgLitArg (LitNumber LitNumInt (fromIntegral tag))       arg_idxs = IM.fromList (zipEqual "mkUbxSum" layout' args0) -      mkTupArgs :: Int -> [SlotTy] -> IM.IntMap StgArg -> [StgArg]-      mkTupArgs _ [] _-        = []-      mkTupArgs arg_idx (slot : slots_left) arg_map-        | Just stg_arg <- IM.lookup arg_idx arg_map-        = stg_arg : mkTupArgs (arg_idx + 1) slots_left arg_map-        | otherwise-        = ubxSumRubbishArg slot : mkTupArgs (arg_idx + 1) slots_left arg_map+      ((_idx,_idx_map,_us,wrapper),slot_args)+        = assert (length arg_idxs <= length sum_slots ) $+          mapAccumL mkTupArg (0,arg_idxs,us,id) sum_slots++      mkTupArg  :: (Int, IM.IntMap StgArg,UniqSupply,StgExpr->StgExpr)+                -> SlotTy+                -> ((Int,IM.IntMap StgArg,UniqSupply,StgExpr->StgExpr), StgArg)+      mkTupArg (arg_idx, arg_map, us, wrapper) slot+         | Just stg_arg <- IM.lookup arg_idx arg_map+         =  case castArg us slot stg_arg of+              -- Slot and arg type missmatched, do a cast+              Just (casted_arg,us',wrapper') ->+                ( (arg_idx+1, arg_map, us', wrapper . wrapper')+                , casted_arg)+              -- Use the arg as-is+              Nothing ->+                ( (arg_idx+1, arg_map, us, wrapper)+                , stg_arg)+         -- Garbage slot, fill with rubbish+         | otherwise+         =  ( (arg_idx+1, arg_map, us, wrapper)+            , ubxSumRubbishArg slot)++      castArg :: UniqSupply -> SlotTy -> StgArg -> Maybe (StgArg,UniqSupply,StgExpr -> StgExpr)+      castArg us slot_ty arg+        -- Cast the argument to the type of the slot if required+        | slotPrimRep slot_ty /= typePrimRep1 (stgArgType arg)+        , out_ty <- primRepToType $ slotPrimRep slot_ty+        , (ops,types) <- unzip $ getCasts (typePrimRep1 $ stgArgType arg) $ typePrimRep1 out_ty+        , not . null $ ops+        = let (us1,us2) = splitUniqSupply us+              cast_uqs = uniqsFromSupply us1+              cast_opts = zip3 ops types cast_uqs+              (_op,out_ty,out_uq) = last cast_opts+              casts = castArgRename cast_opts arg :: StgExpr -> StgExpr+          in Just (StgVarArg (mkCastVar out_uq out_ty),us2,casts)+        -- No need for casting+        | otherwise = Nothing++      tup_args = tag_arg : slot_args     in-      tag_arg : mkTupArgs 0 sum_slots arg_idxs+      -- pprTrace "mkUbxSum" (+      --   text "ty_args (slots)" <+> ppr ty_args $$+      --   text "args0" <+> ppr args0 $$+      --   text "wrapper" <+>+      --       (ppr $ wrapper $ StgLit $ LitChar '_'))+      (tup_args, wrapper)   -- | Return a rubbish value for the given slot type.@@ -688,13 +944,13 @@ -- See Note [aBSENT_SUM_FIELD_ERROR_ID] in "GHC.Core.Make" -- ubxSumRubbishArg :: SlotTy -> StgArg-ubxSumRubbishArg PtrLiftedSlot    = StgVarArg aBSENT_SUM_FIELD_ERROR_ID-ubxSumRubbishArg PtrUnliftedSlot  = StgVarArg aBSENT_SUM_FIELD_ERROR_ID-ubxSumRubbishArg WordSlot   = StgLitArg (LitNumber LitNumWord 0)-ubxSumRubbishArg Word64Slot = StgLitArg (LitNumber LitNumWord64 0)-ubxSumRubbishArg FloatSlot  = StgLitArg (LitFloat 0)-ubxSumRubbishArg DoubleSlot = StgLitArg (LitDouble 0)-ubxSumRubbishArg (VecSlot n e) = StgLitArg (LitRubbish vec_rep)+ubxSumRubbishArg PtrLiftedSlot   = StgVarArg aBSENT_SUM_FIELD_ERROR_ID+ubxSumRubbishArg PtrUnliftedSlot = StgVarArg aBSENT_SUM_FIELD_ERROR_ID+ubxSumRubbishArg WordSlot        = StgLitArg (LitNumber LitNumWord 0)+ubxSumRubbishArg Word64Slot      = StgLitArg (LitNumber LitNumWord64 0)+ubxSumRubbishArg FloatSlot       = StgLitArg (LitFloat 0)+ubxSumRubbishArg DoubleSlot      = StgLitArg (LitDouble 0)+ubxSumRubbishArg (VecSlot n e)   = StgLitArg (LitRubbish TypeLike vec_rep)   where vec_rep = primRepToRuntimeRep (VecRep n e)  --------------------------------------------------------------------------------@@ -789,7 +1045,7 @@ -- | MultiVal a function argument. Never returns an empty list. unariseFunArg :: UnariseEnv -> StgArg -> [StgArg] unariseFunArg rho (StgVarArg x) =-  case lookupVarEnv rho x of+  case lookupRho rho x of     Just (MultiVal [])  -> [voidArg]   -- NB: do not remove void args     Just (MultiVal as)  -> as     Just (UnaryVal arg) -> [arg]@@ -811,7 +1067,7 @@ -- | MultiVal a DataCon argument. Returns an empty list when argument is void. unariseConArg :: UnariseEnv -> InStgArg -> [OutStgArg] unariseConArg rho (StgVarArg x) =-  case lookupVarEnv rho x of+  case lookupRho rho x of     Just (UnaryVal arg) -> [arg]     Just (MultiVal as) -> as      -- 'as' can be empty     Nothing
compiler/GHC/Stg/Utils.hs view
@@ -35,7 +35,7 @@ mkUnarisedIds fs tys = mapM (mkUnarisedId fs) tys  mkUnarisedId :: MonadUnique m => FastString -> UnaryType -> m Id-mkUnarisedId s t = mkSysLocalM s Many t+mkUnarisedId s t = mkSysLocalM s ManyTy t  -- Checks if id is a top level error application. -- isErrorAp_maybe :: Id ->@@ -72,8 +72,7 @@    prim_reps = typePrimRep bndr_ty     _is_poly_alt_tycon tc-        =  isFunTyCon tc-        || isPrimTyCon tc   -- "Any" is lifted but primitive+        =  isPrimTyCon tc   -- "Any" is lifted but primitive         || isFamilyTyCon tc -- Type family; e.g. Any, or arising from strict                             -- function application where argument has a                             -- type-family type
compiler/GHC/StgToByteCode.hs view
@@ -5,7 +5,6 @@ {-# LANGUAGE FlexibleContexts           #-}  {-# OPTIONS_GHC -fprof-auto-top #-}-{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}  -- --  (c) The University of Glasgow 2002-2006@@ -1724,7 +1723,7 @@         LitChar {}      -> code WordRep         LitNullAddr     -> code AddrRep         LitString {}    -> code AddrRep-        LitRubbish rep  -> case runtimeRepPrimRep (text "pushLiteral") rep of+        LitRubbish _ rep-> case runtimeRepPrimRep (text "pushLiteral") rep of                              [pr] -> code pr                              _    -> pprPanic "pushLiteral" (ppr lit)         LitNumber nt _  -> case nt of
compiler/GHC/StgToCmm.hs view
@@ -188,10 +188,10 @@              (lit,decl) = if asString               then mkByteStringCLit label str-              else mkFileEmbedLit label $ unsafePerformIO $ do+              else unsafePerformIO $ do                      bFile <- newTempName logger tmpfs (stgToCmmTmpDir cfg) TFL_CurrentModule ".dat"                      BS.writeFile bFile str-                     return bFile+                     return $ mkFileEmbedLit label bFile (BS.length str)         emitDecl decl         addBindC (litIdInfo (stgToCmmPlatform cfg) id mkLFStringLit lit) 
compiler/GHC/StgToCmm/Env.hs view
@@ -36,6 +36,7 @@ import GHC.Cmm.Graph import GHC.Types.Name import GHC.Core.Type+import GHC.Core.TyCo.Compare( eqType ) import GHC.Builtin.Types.Prim import GHC.Types.Unique.FM import GHC.Types.Var.Env
compiler/GHC/StgToCmm/Heap.hs view
@@ -6,8 +6,6 @@ -- ----------------------------------------------------------------------------- -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}- module GHC.StgToCmm.Heap (         getVirtHp, setVirtHp, setRealHp,         getHpRelOffset,@@ -612,10 +610,6 @@   gc_id       <- newBlockId    let-    Just alloc_lit = mb_alloc_lit--    bump_hp   = cmmOffsetExprB platform hpExpr alloc_lit-     -- Sp overflow if ((old + 0) - CmmHighStack < SpLim)     -- At the beginning of a function old + 0 = Sp     -- See Note [Single stack check]@@ -630,8 +624,6 @@     -- HpLim points to the LAST WORD of valid allocation space.     hp_oflo = CmmMachOp (mo_wordUGt platform) [hpExpr, hpLimExpr] -    alloc_n = mkAssign hpAllocReg alloc_lit-   case mb_stk_hwm of     Nothing -> return ()     Just stk_hwm -> tickyStackCheck@@ -646,12 +638,14 @@         | checkYield && isJust mb_stk_hwm -> emitLabel loop_header_id     _otherwise -> return () -  if isJust mb_alloc_lit-    then do+  case mb_alloc_lit of+    Just alloc_lit -> do+     let bump_hp   = cmmOffsetExprB platform hpExpr alloc_lit+         alloc_n = mkAssign hpAllocReg alloc_lit      tickyHeapCheck      emitAssign hpReg bump_hp      emit =<< mkCmmIfThen' hp_oflo (alloc_n <*> mkBranch gc_id) (Just False)-    else+    Nothing ->       when (checkYield && not omit_yields) $ do          -- Yielding if HpLim == 0          let yielding = CmmMachOp (mo_wordEq platform)
compiler/GHC/StgToCmm/Lit.hs view
@@ -50,7 +50,7 @@ cgLit (LitString s) =   CmmLit <$> newByteStringCLit s  -- not unpackFS; we want the UTF-8 byte stream.-cgLit (LitRubbish rep) =+cgLit (LitRubbish _ rep) =   case expectOnly "cgLit" prim_reps of -- Note [Post-unarisation invariants]     VoidRep     -> panic "cgLit:VoidRep"   -- ditto     LiftedRep   -> idInfoToAmode <$> getCgIdInfo unitDataConId
compiler/GHC/StgToCmm/Ticky.hs view
@@ -154,7 +154,6 @@ import qualified Data.Char import Control.Monad ( when, unless ) import GHC.Types.Id.Info-import GHC.Utils.Trace import GHC.StgToCmm.Env (getCgInfo_maybe) import Data.Coerce (coerce) import GHC.Utils.Json@@ -887,7 +886,7 @@   Just (tycon, _) ->     let anyOf us = getUnique tycon `elem` us in     case () of-      _ | anyOf [funTyConKey] -> '>'+      _ | anyOf [fUNTyConKey] -> '>'         | anyOf [charTyConKey] -> 'C'         | anyOf [charPrimTyConKey] -> 'c'         | anyOf [doubleTyConKey] -> 'D'
+ compiler/GHC/StgToJS.hs view
@@ -0,0 +1,216 @@+module GHC.StgToJS+  ( stgToJS+  )+where++import GHC.StgToJS.CodeGen+++-- Note [StgToJS design]+-- ~~~~~~~~~~~~~~~~~~~~~+--+-- StgToJS ("JS backend") is adapted from GHCJS [GHCJS2013].+--+-- Haskell to JavaScript+-- ~~~~~~~~~~~~~~~~~~~~~+-- StgToJS converts STG into a JavaScript AST (in GHC.JS) that has been adapted+-- from JMacro [JMacro].+--+-- Tail calls: translated code is tail call optimized through a trampoline,+-- since JavaScript implementations don't always support tail calls.+--+-- JavaScript ASTs are then optimized. A dataflow analysis is performed and then+-- dead code and redundant assignments are removed.+--+-- Primitives+-- ~~~~~~~~~~+-- Haskell primitives have to be represented as JavaScript values. This is done+-- as follows:+--+--  - Int#/Int32#     -> number in Int32 range+--  - Int16#          -> number in Int16 range+--  - Int8#           -> number in Int8 range+--  - Word#/Word32#   -> number in Word32 range+--  - Word16#         -> number in Word16 range+--  - Word8#          -> number in Word8 range+--+--  - Float#/Double#  -> both represented as Javascript Double (no Float!)+--+--  - Int64#          -> represented with two fields:+--                          high -> number in Int32 range+--                          low  -> number in Word32 range+--  - Word64#         -> represented with two fields: high, low+--                          high -> number in Word32 range+--                          low  -> number in Word32 range+--+--  - Addr#           -> represented with two fields: array (used as a namespace) and index+--  - StablePtr#      -> similar to Addr# with array fixed to h$stablePtrBuf+--+--  - JSVal#          -> any Javascript object (used to pass JS objects via FFI)+--+--  - TVar#, MVar#, etc. are represented with JS objects+--+-- Foreign JavaScript imports+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~+-- StgToJS supports inline JavaScript code. Example:+--+--    > foreign import javascript unsafe+--    >   "((x,y) => x + y)"+--    >   plus :: Int -> Int -> Int+--+-- Currently the JS backend only supports functions as JS imports.+--+-- In comparison, GHCJS supports JavaScript snippets with $1, $2... variables+-- as placeholders for the arguments. It requires a JavaScript parser that the+-- JS backend lacks. In GHCJS, the parser is inherited from JMacro and supports+-- local variable declarations, loops, etc. Local variables are converted to+-- hygienic names to avoid capture.+--+-- Primitives that are represented as multiple values (Int64#, Word64#, Addr#)+-- are passed to FFI functions with multiple arguments.+--+-- Interruptible convention: FFI imports with the "interruptible" calling+-- convention are passed an extra argument (usually named "$c") that is a+-- continuation function. The FFI function must call this function to return to+-- Haskell code.+--+-- Unboxed tuples: returning an unboxed tuple can be done with the predefined+-- macros RETURN_UBX_TUPn where n is the size of the tuples. Internally it uses+-- predefined "h$retN" global variables to pass additional values; the first+-- element of the tuple is returned normally.+--+-- Memory management+-- ~~~~~~~~~~~~~~~~~+-- Heap objects are represented as JavaScript values.+--+-- Most heap objects are represented generically as JavaScript "objects" (hash+-- maps). However, some Haskell heap objects can use use a more memory efficient+-- JavaScript representation: number, string... An example of a consequence of+-- this is that both Int# and Int are represented the same as a JavaScript+-- number. JavaScript introspection (e.g. typeof) is used to differentiate+-- heap object representations when necessary.+--+-- Generic representation: objects on the heap ("closures") are represented as+-- JavaScript objects with the following fields:+--+--  { f   -- (function) entry function + info table+--  , d1  -- two fields of payload+--  , d2+--  , m   -- GC mark+--  , cc  -- optional cost-center+--  }+--+-- Payload: payload only consists of two fields (d1, d2). When more than two+-- fields of payload are required, the second field is itself an object.+--    payload []         ==> { d1 = null, d2 = null                   }+--    payload [a]        ==> { d1 = a   , d2 = null                   }+--    payload [a,b]      ==> { d1 = a   , d2 = b                      }+--    payload [a,b,c]    ==> { d1 = a   , d2 = { d1 = b, d2 = c}      }+--    payload [a,b,c...] ==> { d1 = a   , d2 = { d1 = b, d2 = c, ...} }+--+-- Entry function/ info tables: JavaScript functions are JavaScript objects. If+-- "f" is a function, we can:+--    - call it, e.g. "f(arg0,arg1...)"+--    - get/set its fields, e.g. "f.xyz = abc"+-- This is used to implement the equivalent of tables-next-to-code in+-- JavaScript: every heap object has an entry function "f" that also contains+-- some metadata (info table) about the Haskell object:+--    { t     -- object type+--    , size  -- number of fields in the payload (-1 if variable layout)+--    , i     -- (array) fields layout (empty if variable layout)+--    , n     -- (string) object name for easier dubugging+--    , a     -- constructor tag / fun arity+--    , r     -- ??+--    , s     -- static references?+--    , m     -- GC mark?+--    }+--+-- Payloads for each kind of heap object:+--+-- THUNK =+--  { f  = returns the object reduced to WHNF+--  , m  = ?+--  , d1 = ?+--  , d2 = ?+--  }+--+-- FUN =+--  { f  = function itself+--  , m  = ?+--  , d1 = free variable 1+--  , d2 = free variable 2+--  }+--+-- There are two different kinds of partial application:+--  - pap_r   : pre-generated PAP that contains r registers+--  - pap_gen : generic PAP, contains any number of registers+--+-- PAP =+--  { f  = ?+--  , m  = ?+--  , d1 = function+--  , d2 =+--    { d1 & 0xff = number of args (PAP arity)+--    , d1 >> 8   = number of registers (r for h$pap_r)+--    , d2, d3... = args (r)+--    }+--  }+--+-- CON =+--  { f  = entry function of the datacon worker+--  , m  = 0+--  , d1 = first arg+--  , d2 = arity = 2: second arg+--         arity > 2: { d1, d2, ...} object with remaining args (starts with "d1 = x2"!)+--  }+--+-- BLACKHOLE =+--  { f  = h$blackhole+--  , m  = ?+--  , d1 = owning TSO+--  , d2 = waiters array+--  }+--+-- StackFrame closures are *not* represented as JS objects. Instead they are+-- "unpacked" in the stack, i.e. a stack frame occupies a few slots in the JS+-- array representing the stack ("h$stack").+--+-- When a shared thunk is entered, it is overriden with a black hole ("eager+-- blackholing") and an update frame is pushed on the stack.+--+-- Stack: the Haskell stack is implemented with a dynamically growing JavaScript+-- array ("h$stack").+--  TODO: does it shrink sometimes?+--  TODO: what are the elements of the stack? one JS object per stack frame?+--+--+-- Interaction with JavaScript's garbage collector+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- Using JS objects to represent Haskell heap objects means that JS's GC does+-- most of the memory management work.+--+-- However, GHC extends Haskell with features that rely on GC layer violation+-- (weak references, finalizers, etc.). To support these features, a heap scan+-- is can be performed (using TSOs, StablePtr, etc. as roots) to mark reachable+-- objects. Scanning the heap is an expensive operation, but fortunately it+-- doesn't need to happen too often and it can be disabled.+--+-- TODO: importance of eager blackholing+--+-- Concurrency+-- ~~~~~~~~~~~+-- The scheduler is implemented in JS and runs in a single JavaScript thread+-- (similarly to the C RTS not using `-threaded`).+--+-- The scheduler relies on callbacks/continuations to interact with other JS+-- codes (user interface, etc.). In particular, safe foreign import can use "$c"+-- as a continuation function to return to Haskell code.+--+-- TODO: is this still true since 2013 or are we using more recent JS features now?+-- TODO: synchronous threads+--+--+-- REFERENCES+--  * [GHCJS2013] "Demo Proposal: GHCJS, Concurrent Haskell in the Browser", Luite Stegeman,+--    2013 (https://www.haskell.org/haskell-symposium/2013/ghcjs.pdf)+--  * [JMacro] https://hackage.haskell.org/package/jmacro
+ compiler/GHC/StgToJS/Apply.hs view
@@ -0,0 +1,1152 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE BlockArguments #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Apply+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+--+-- Module that deals with expression application in JavaScript. In some cases we+-- rely on pre-generated functions that are bundled with the RTS (see rtsApply).+-----------------------------------------------------------------------------++module GHC.StgToJS.Apply+  ( genApp+  , rtsApply+  )+where++import GHC.Prelude hiding ((.|.))++import GHC.JS.Syntax+import GHC.JS.Make++import GHC.StgToJS.Arg+import GHC.StgToJS.Closure+import GHC.StgToJS.DataCon+import GHC.StgToJS.ExprCtx+import GHC.StgToJS.Heap+import GHC.StgToJS.Monad+import GHC.StgToJS.Types+import GHC.StgToJS.Profiling+import GHC.StgToJS.Regs+import GHC.StgToJS.CoreUtils+import GHC.StgToJS.Utils+import GHC.StgToJS.Rts.Types+import GHC.StgToJS.Stack+import GHC.StgToJS.Ids++import GHC.Types.Literal+import GHC.Types.Id+import GHC.Types.Id.Info+import GHC.Types.CostCentre++import GHC.Stg.Syntax++import GHC.Builtin.Names++import GHC.Core.TyCon+import GHC.Core.DataCon+import GHC.Core.Type hiding (typeSize)++import GHC.Utils.Encoding+import GHC.Utils.Misc+import GHC.Utils.Monad+import GHC.Utils.Panic+import GHC.Utils.Outputable (vcat, ppr)+import GHC.Data.FastString++import qualified Data.Bits as Bits+import Data.Monoid+import Data.Array++-- | Pre-generated functions for fast Apply.+-- These are bundled with the RTS.+rtsApply :: StgToJSConfig -> JStat+rtsApply cfg = BlockStat $+  map (specApply cfg) applySpec+  ++ map (pap cfg) specPap+  ++ [ mkApplyArr+     , genericStackApply cfg+     , genericFastApply  cfg+     , zeroApply cfg+     , updates   cfg+     , papGen    cfg+     , moveRegs2+     , selectors cfg+     ]+++-- | Generate an application of some args to an Id.+--+-- The case where args is null is common as it's used to generate the evaluation+-- code for an Id.+genApp+  :: HasDebugCallStack+  => ExprCtx+  -> Id+  -> [StgArg]+  -> G (JStat, ExprResult)+genApp ctx i args++    -- Case: unpackCStringAppend# "some string"# str+    --+    -- Generates h$appendToHsStringA(str, "some string"), which has a faster+    -- decoding loop.+    | [StgLitArg (LitString bs), x] <- args+    , [top] <- concatMap typex_expr (ctxTarget ctx)+    , getUnique i == unpackCStringAppendIdKey+    , d <- utf8DecodeByteString bs+    = do+        prof <- csProf <$> getSettings+        let profArg = if prof then [jCafCCS] else []+        a <- genArg x+        return ( top |= app "h$appendToHsStringA" ([toJExpr d, toJExpr a] ++ profArg)+               , ExprInline Nothing+               )++    -- let-no-escape+    | Just n <- ctxLneBindingStackSize ctx i+    = do+      as'      <- concatMapM genArg args+      ei       <- varForEntryId i+      let ra = mconcat . reverse $+                 zipWith (\r a -> toJExpr r |= a) [R1 ..] as'+      p <- pushLneFrame n ctx+      a <- adjSp 1 -- for the header (which will only be written when the thread is suspended)+      return (ra <> p <> a <> returnS ei, ExprCont)++    -- proxy#+    | [] <- args+    , getUnique i == proxyHashKey+    , [top] <- concatMap typex_expr (ctxTarget ctx)+    = return (top |= null_, ExprInline Nothing)++    -- unboxed tuple or strict type: return fields individually+    | [] <- args+    , isUnboxedTupleType (idType i) || isStrictType (idType i)+    = do+      a <- storeIdFields i (ctxTarget ctx)+      return (a, ExprInline Nothing)++    -- Handle alternative heap object representation: in some cases, a heap+    -- object is not represented as a JS object but directly as a number or a+    -- string. I.e. only the payload is stored because the box isn't useful.+    -- It happens for "Int Int#" for example: no need to box the Int# in JS.+    --+    -- We must check that:+    --  - the object is subject to the optimization (cf isUnboxable predicate)+    --  - we know that it is already evaluated (cf ctxIsEvaluated), otherwise we+    --  need to evaluate it properly first.+    --+    -- In which case we generate a dynamic check (using isObject) that either:+    --  - returns the payload of the heap object, if it uses the generic heap+    --  object representation+    --  - returns the object directly, otherwise+    | [] <- args+    , [vt] <- idVt i+    , isUnboxable vt+    , ctxIsEvaluated ctx i+    = do+      let c = head (concatMap typex_expr $ ctxTarget ctx)+      is <- varsForId i+      case is of+        [i'] ->+          return ( c |= if_ (isObject i') (closureField1 i') i'+                 , ExprInline Nothing+                 )+        _ -> panic "genApp: invalid size"++    -- case of Id without args and known to be already evaluated: return fields+    -- individually+    | [] <- args+    , ctxIsEvaluated ctx i || isStrictType (idType i)+    = do+      a <- storeIdFields i (ctxTarget ctx)+      -- optional runtime assert for detecting unexpected thunks (unevaluated)+      settings <- getSettings+      let ww = case concatMap typex_expr (ctxTarget ctx) of+                 [t] | csAssertRts settings ->+                         ifS (isObject t .&&. isThunk t)+                             (appS "throw" [String "unexpected thunk"]) -- yuck+                             mempty+                 _   -> mempty+      return (a `mappend` ww, ExprInline Nothing)+++    -- Case: "newtype" datacon wrapper+    --+    -- If the wrapped argument is known to be already evaluated, then we don't+    -- need to enter it.+    | DataConWrapId dc <- idDetails i+    , isNewTyCon (dataConTyCon dc)+    = do+      as <- concatMapM genArg args+      case as of+        [ai] -> do+          let t = head (concatMap typex_expr (ctxTarget ctx))+              a' = case args of+                [StgVarArg a'] -> a'+                _              -> panic "genApp: unexpected arg"+          if isStrictId a' || ctxIsEvaluated ctx a'+            then return (t |= ai, ExprInline Nothing)+            else return (returnS (app "h$e" [ai]), ExprCont)+        _ -> panic "genApp: invalid size"++    -- no args and Id can't be a function: just enter it+    | [] <- args+    , idFunRepArity i == 0+    , not (might_be_a_function (idType i))+    = do+      enter_id <- genIdArg i >>=+                    \case+                       [x] -> return x+                       xs  -> pprPanic "genApp: unexpected multi-var argument"+                                (vcat [ppr (length xs), ppr i])+      return (returnS (app "h$e" [enter_id]), ExprCont)++    -- fully saturated global function:+    --  - deals with arguments+    --  - jumps into the function+    | n <- length args+    , n /= 0+    , idFunRepArity i == n+    , not (isLocalId i)+    , isStrictId i+    = do+      as' <- concatMapM genArg args+      is  <- assignAll jsRegsFromR1 <$> varsForId i+      jmp <- jumpToII i as' is+      return (jmp, ExprCont)++    -- oversaturated function:+    --  - push continuation with extra args+    --  - deals with arguments+    --  - jumps into the function+    | idFunRepArity i < length args+    , isStrictId i+    , idFunRepArity i > 0+    = do+      let (reg,over) = splitAt (idFunRepArity i) args+      reg' <- concatMapM genArg reg+      pc   <- pushCont over+      is   <- assignAll jsRegsFromR1 <$> varsForId i+      jmp  <- jumpToII i reg' is+      return (pc <> jmp, ExprCont)++    -- generic apply:+    --  - try to find a pre-generated apply function that matches+    --  - use it if any+    --  - otherwise use generic apply function h$ap_gen_fast+    | otherwise+    = do+      is  <- assignAll jsRegsFromR1 <$> varsForId i+      jmp <- jumpToFast args is+      return (jmp, ExprCont)++-- avoid one indirection for global ids+-- fixme in many cases we can also jump directly to the entry for local?+jumpToII :: Id -> [JExpr] -> JStat -> G JStat+jumpToII i vars load_app_in_r1+  | isLocalId i = do+     ii <- varForId i+     return $ mconcat+      [ assignAllReverseOrder jsRegsFromR2 vars+      , load_app_in_r1+      , returnS (closureEntry ii)+      ]+  | otherwise   = do+     ei <- varForEntryId i+     return $ mconcat+      [ assignAllReverseOrder jsRegsFromR2 vars+      , load_app_in_r1+      , returnS ei+      ]++-- | Try to use a specialized pre-generated application function.+-- If there is none, use h$ap_gen_fast instead+jumpToFast :: HasDebugCallStack => [StgArg] -> JStat -> G JStat+jumpToFast args load_app_in_r1 = do+  -- get JS expressions for every argument+  -- Arguments may have more than one expression (e.g. Word64#)+  vars <- concatMapM genArg args+  -- try to find a specialized apply function+  let spec = mkApplySpec RegsConv args vars+  ap_fun <- selectApply spec+  pure $ mconcat+    [ assignAllReverseOrder jsRegsFromR2 vars+    , load_app_in_r1+    , case ap_fun of+        -- specialized apply: no tag+        Right fun -> returnS (ApplExpr fun [])+        -- generic apply: pass a tag indicating number of args/slots+        Left  fun -> returnS (ApplExpr fun [specTagExpr spec])+    ]++-- | Calling convention for an apply function+data ApplyConv+  = RegsConv  -- ^ Fast calling convention: use registers+  | StackConv -- ^ Slow calling convention: use the stack+  deriving (Show,Eq,Ord)++-- | Name of the generic apply function+genericApplyName :: ApplyConv -> FastString+genericApplyName = \case+  RegsConv  -> "h$ap_gen_fast"+  StackConv -> "h$ap_gen"++-- | Expr of the generic apply function+genericApplyExpr :: ApplyConv -> JExpr+genericApplyExpr conv = var (genericApplyName conv)+++-- | Return the name of the specialized apply function for the given number of+-- args, number of arg variables, and calling convention.+specApplyName :: ApplySpec -> FastString+specApplyName = \case+  -- specialize a few for compiler performance (avoid building FastStrings over+  -- and over for common cases)+  ApplySpec RegsConv  0 0    -> "h$ap_0_0_fast"+  ApplySpec StackConv 0 0    -> "h$ap_0_0"+  ApplySpec RegsConv  1 0    -> "h$ap_1_0_fast"+  ApplySpec StackConv 1 0    -> "h$ap_1_0"+  ApplySpec RegsConv  1 1    -> "h$ap_1_1_fast"+  ApplySpec StackConv 1 1    -> "h$ap_1_1"+  ApplySpec RegsConv  1 2    -> "h$ap_1_2_fast"+  ApplySpec StackConv 1 2    -> "h$ap_1_2"+  ApplySpec RegsConv  2 1    -> "h$ap_2_1_fast"+  ApplySpec StackConv 2 1    -> "h$ap_2_1"+  ApplySpec RegsConv  2 2    -> "h$ap_2_2_fast"+  ApplySpec StackConv 2 2    -> "h$ap_2_2"+  ApplySpec RegsConv  2 3    -> "h$ap_2_3_fast"+  ApplySpec StackConv 2 3    -> "h$ap_2_3"+  ApplySpec conv nargs nvars -> mkFastString $ mconcat+                                  [ "h$ap_", show nargs+                                  , "_"    , show nvars+                                  , case conv of+                                      RegsConv  -> "_fast"+                                      StackConv -> ""+                                  ]++-- | Return the expression of the specialized apply function for the given+-- number of args, number of arg variables, and calling convention.+--+-- Warning: the returned function may not be generated! Use specApplyExprMaybe+-- if you want to ensure that it exists.+specApplyExpr :: ApplySpec -> JExpr+specApplyExpr spec = var (specApplyName spec)++-- | Return the expression of the specialized apply function for the given+-- number of args, number of arg variables, and calling convention.+-- Return Nothing if it isn't generated.+specApplyExprMaybe :: ApplySpec -> Maybe JExpr+specApplyExprMaybe spec =+  if spec `elem` applySpec+    then Just (specApplyExpr spec)+    else Nothing++-- | Make an ApplySpec from a calling convention, a list of Haskell args, and a+-- list of corresponding JS variables+mkApplySpec :: ApplyConv -> [StgArg] -> [JExpr] -> ApplySpec+mkApplySpec conv args vars = ApplySpec+  { specConv = conv+  , specArgs = length args+  , specVars = length vars+  }++-- | Find a specialized application function if there is one+selectApply+  :: ApplySpec+  -> G (Either JExpr JExpr) -- ^ the function to call (Left for generic, Right for specialized)+selectApply spec =+  case specApplyExprMaybe spec of+    Just e  -> return (Right e)+    Nothing -> return (Left (genericApplyExpr (specConv spec)))+++-- | Apply specification+data ApplySpec = ApplySpec+  { specConv :: !ApplyConv -- ^ Calling convention+  , specArgs :: !Int       -- ^ number of Haskell arguments+  , specVars :: !Int       -- ^ number of JavaScript variables for the arguments+  }+  deriving (Show,Eq,Ord)++-- | List of specialized apply function templates+applySpec :: [ApplySpec]+applySpec = [ ApplySpec conv nargs nvars+            | conv  <- [RegsConv, StackConv]+            , nargs <- [0..4]+            , nvars <- [max 0 (nargs-1)..(nargs*2)]+            ]++-- | Generate a tag for the given ApplySpec+--+-- Warning: tag doesn't take into account the calling convention+specTag :: ApplySpec -> Int+specTag spec = Bits.shiftL (specVars spec) 8 Bits..|. (specArgs spec)++-- | Generate a tag expression for the given ApplySpec+specTagExpr :: ApplySpec -> JExpr+specTagExpr = toJExpr . specTag++-- | Build arrays to quickly lookup apply functions+--+--  h$apply[r << 8 | n] = function application for r regs, n args+--  h$paps[r]           = partial application for r registers (number of args is in the object)+mkApplyArr :: JStat+mkApplyArr = mconcat+  [ TxtI "h$apply" ||= toJExpr (JList [])+  , TxtI "h$paps"  ||= toJExpr (JList [])+  , ApplStat (var "h$initStatic" .^ "push")+    [ ValExpr $ JFunc [] $ jVar \i -> mconcat+        [ i |= zero_+        , WhileStat False (i .<. Int 65536) $ mconcat+            [ var "h$apply" .! i |= var "h$ap_gen"+            , preIncrS i+            ]+        , i |= zero_+        , WhileStat False (i .<. Int 128) $ mconcat+            [ var "h$paps" .! i |= var "h$pap_gen"+            , preIncrS i+            ]+        , mconcat (map assignSpec applySpec)+        , mconcat (map assignPap specPap)+        ]+    ]+  ]+  where+    assignSpec :: ApplySpec -> JStat+    assignSpec spec = case specConv spec of+      -- both fast/slow (regs/stack) specialized apply functions have the same+      -- tags. We store the stack ones in the array because they are used as+      -- continuation stack frames.+      StackConv -> var "h$apply" .! specTagExpr spec |= specApplyExpr spec+      RegsConv  -> mempty++    assignPap :: Int -> JStat+    assignPap p = var "h$paps" .! toJExpr p |=+                      (var (mkFastString $ ("h$pap_" ++ show p)))++-- | Push a continuation on the stack+--+-- First push the given args, then push an apply function (specialized if+-- possible, otherwise the generic h$ap_gen function).+pushCont :: HasDebugCallStack+         => [StgArg]+         -> G JStat+pushCont args = do+  vars <- concatMapM genArg args+  let spec = mkApplySpec StackConv args vars+  selectApply spec >>= \case+    Right app -> push $ reverse $ app : vars+    Left  app -> push $ reverse $ app : specTagExpr spec : vars++-- | Generic stack apply function (h$ap_gen) that can do everything, but less+-- efficiently than other more specialized functions.+--+-- Stack layout:+--  -3: ...+--  -2: args+--  -1: tag (number of arg slots << 8 | number of args)+--+-- Regs:+--  R1 = applied closure+--+genericStackApply :: StgToJSConfig -> JStat+genericStackApply cfg = closure info body+  where+    -- h$ap_gen body+    body = jVar \cf ->+      [ traceRts cfg (jString "h$ap_gen")+      , cf |= closureEntry r1+        -- switch on closure type+      , SwitchStat (entryClosureType cf)+        [ (toJExpr Thunk    , thunk_case cfg cf)+        , (toJExpr Fun      , fun_case cf (funArity' cf))+        , (toJExpr Pap      , fun_case cf (papArity r1))+        , (toJExpr Blackhole, blackhole_case cfg)+        ]+        (default_case cf)+      ]++    -- info table for h$ap_gen+    info = ClosureInfo+      { ciVar     = TxtI "h$ap_gen"+      , ciRegs    = CIRegs 0 [PtrV] -- closure to apply to+      , ciName    = "h$ap_gen"+      , ciLayout  = CILayoutVariable+      , ciType    = CIStackFrame+      , ciStatic  = mempty+      }++    default_case cf = appS "throw" [jString "h$ap_gen: unexpected closure type "+                                    + (entryClosureType cf)]++    thunk_case cfg cf = mconcat+      [ profStat cfg pushRestoreCCS+      , returnS cf+      ]++    blackhole_case cfg = mconcat+      [ push' cfg [r1, var "h$return"]+      , returnS (app "h$blockOnBlackhole" [r1])+      ]++    fun_case c arity = jVar \tag needed_args needed_regs given_args given_regs newTag newAp p dat ->+      [ tag         |= stack .! (sp - 1) -- tag on the stack+      , given_args  |= mask8 tag         -- indicates the number of passed args+      , given_regs  |= tag .>>. 8        -- and the number of passed values for registers+      , needed_args |= mask8 arity+      , needed_regs |= arity .>>. 8+      , traceRts cfg (jString "h$ap_gen: args: " + given_args+                    + jString " regs: " + given_regs)+      , ifBlockS (given_args .===. needed_args)+        --------------------------------+        -- exactly saturated application+        --------------------------------+        [ traceRts cfg (jString "h$ap_gen: exact")+        -- Set registers to register values on the stack+        , loop 0 (.<. given_regs) \i -> mconcat+            [ appS "h$setReg" [i+2, stack .! (sp-2-i)]+            , postIncrS i+            ]+        -- drop register values from the stack+        , sp |= sp - given_regs - 2+        -- enter closure in R1+        , returnS c+        ]+        [ ifBlockS (given_args .>. needed_args)+            ----------------------------+            -- oversaturated application+            ----------------------------+            [ traceRts cfg (jString "h$ap_gen: oversat: arity: " + needed_args+                          + jString " regs: " + needed_regs)+            -- load needed register values+            , loop 0 (.<. needed_regs) \i -> mconcat+                [ traceRts cfg (jString "h$ap_gen: loading register: " + i)+                , appS "h$setReg" [i+2, stack .! (sp-2-i)]+                , postIncrS i+                ]+            -- compute new tag with consumed register values and args removed+            , newTag |= ((given_regs-needed_regs).<<.8) .|. (given_args - needed_args)+            -- find application function for the remaining regs/args+            , newAp |= var "h$apply" .! newTag+            , traceRts cfg (jString "h$ap_gen: next: " + (newAp .^ "n"))++            -- Drop used registers from the stack.+            -- Test if the application function needs a tag and push it.+            , ifS (newAp .===. var "h$ap_gen")+                   ((sp |= sp - needed_regs) <> (stack .! (sp - 1) |= newTag))+                   (sp |= sp - needed_regs - 1)++            -- Push generic application function as continuation+            , stack .! sp |= newAp++            -- Push "current thread CCS restore" function as continuation+            , profStat cfg pushRestoreCCS++            -- enter closure in R1+            , returnS c+            ]++            -----------------------------+            -- undersaturated application+            -----------------------------+            [ traceRts cfg (jString "h$ap_gen: undersat")+            -- find PAP entry function corresponding to given_regs count+            , p      |= var "h$paps" .! given_regs++            -- build PAP payload: R1 + tag + given register values+            , newTag |= ((needed_regs-given_regs) .<<. 8) .|. (needed_args-given_args)+            , dat    |= toJExpr [r1, newTag]+            , loop 0 (.<. given_regs) \i -> mconcat+                [ (dat .^ "push") `ApplStat` [stack .! (sp - i - 2)]+                , postIncrS i+                ]++            -- remove register values from the stack.+            , sp  |= sp - given_regs - 2++            -- alloc PAP closure, store reference to it in R1.+            , r1  |= initClosure cfg p dat jCurrentCCS++            -- return to the continuation on the stack+            , returnStack+            ]+        ]+      ]++-- | Generic fast apply function (h$ap_gen_fast) that can do everything, but less+-- efficiently than other more specialized functions.+--+-- Signature tag in argument. Tag: (regs << 8 | arity)+--+-- Regs:+--  R1 = closure to apply to+--+genericFastApply :: StgToJSConfig -> JStat+genericFastApply s =+   TxtI "h$ap_gen_fast" ||= jLam \tag -> jVar \c ->+      [traceRts s (jString "h$ap_gen_fast: " + tag)+      , c |= closureEntry r1+      , SwitchStat (entryClosureType c)+        [ (toJExpr Thunk, traceRts s (jString "h$ap_gen_fast: thunk")+           <> pushStackApply c tag+           <> returnS c)+        , (toJExpr Fun, jVar \farity ->+                               [ farity |= funArity' c+                               , traceRts s (jString "h$ap_gen_fast: fun " + farity)+                               , funCase c tag farity+                               ])+        , (toJExpr Pap, jVar \parity ->+                               [ parity |= papArity r1+                               , traceRts s (jString "h$ap_gen_fast: pap " + parity)+                               , funCase c tag parity+                               ])+        , (toJExpr Con, traceRts s (jString "h$ap_gen_fast: con")+            <> jwhenS (tag .!=. 0)+                (appS "throw" [jString "h$ap_gen_fast: invalid apply"])+                        <> returnS c)+        , (toJExpr Blackhole, traceRts s (jString "h$ap_gen_fast: blackhole")+            <> pushStackApply c tag+            <> push' s [r1, var "h$return"]+            <> returnS (app "h$blockOnBlackhole" [r1]))+        ] $ appS "throw" [jString "h$ap_gen_fast: unexpected closure type: " + entryClosureType c]+      ]++  where+     -- thunk: push everything to stack frame, enter thunk first+    pushStackApply :: JExpr -> JExpr -> JStat+    pushStackApply _c tag =+      jVar \ap ->+        [ pushAllRegs tag+        , ap |= var "h$apply" .! tag+        , ifS (ap .===. var "h$ap_gen")+                ((sp |= sp + 2) <> (stack .! (sp-1) |= tag))+                (sp |= sp + 1)+        , stack .! sp |= ap+        , profStat s pushRestoreCCS+        ]++    funCase :: JExpr -> JExpr -> JExpr -> JStat+    funCase c tag arity =+      jVar \ar myAr myRegs regsStart newTag newAp dat p ->+        [ ar     |= mask8 arity+        , myAr   |= mask8 tag+        , myRegs |= tag .>>. 8+        , traceRts s (jString "h$ap_gen_fast: args: " + myAr+                      + jString " regs: "             + myRegs)+        , ifS (myAr .===. ar)+        -- call the function directly+          (traceRts s (jString "h$ap_gen_fast: exact") <> returnS c)+          (ifBlockS (myAr .>. ar)+          -- push stack frame with remaining args, then call fun+           [ traceRts s (jString "h$ap_gen_fast: oversat " + sp)+           , regsStart |= (arity .>>. 8) + 1+           , sp |= sp + myRegs - regsStart + 1+           , traceRts s (jString "h$ap_gen_fast: oversat " + sp)+           , pushArgs regsStart myRegs+           , newTag |= ((myRegs-( arity.>>.8)).<<.8).|.myAr-ar+           , newAp |= var "h$apply" .! newTag+           , ifS (newAp .===. var "h$ap_gen")+                 ((sp |= sp + 2) <> (stack .! (sp - 1) |= newTag))+                 (sp |= sp + 1)+           , stack .! sp |= newAp+           , profStat s pushRestoreCCS+           , returnS c+           ]+          -- else+           [traceRts s (jString "h$ap_gen_fast: undersat: " + myRegs + jString " " + tag)+           , jwhenS (tag .!=. 0) $ mconcat+               [ p |= var "h$paps" .! myRegs+               , dat |= toJExpr [r1, ((arity .>>. 8)-myRegs)*256+ar-myAr]+               , loop 0 (.<. myRegs)+                 (\i -> (dat .^ "push")+                   `ApplStat` [app "h$getReg" [i+2]] <> postIncrS i)+               , r1 |= initClosure s p dat jCurrentCCS+               ]+           , returnStack+           ])+        ]+++    pushAllRegs :: JExpr -> JStat+    pushAllRegs tag =+      jVar \regs ->+        [ regs |= tag .>>. 8+        , sp |= sp + regs+        , SwitchStat regs (map pushReg [65,64..2]) mempty+        ]+      where+        pushReg :: Int -> (JExpr, JStat)+        pushReg r = (toJExpr (r-1),  stack .! (sp - toJExpr (r - 2)) |= jsReg r)++    pushArgs :: JExpr -> JExpr -> JStat+    pushArgs start end =+      loop end (.>=.start) (\i -> traceRts s (jString "pushing register: " + i)+                             <> (stack .! (sp + start - i) |= app "h$getReg" [i+1])+                             <> postDecrS i+                           )++-- | Make specialized apply function for the given ApplySpec+specApply :: StgToJSConfig -> ApplySpec -> JStat+specApply cfg spec@(ApplySpec conv nargs nvars) =+  let fun_name = specApplyName spec+  in case conv of+    RegsConv  -> fastApply  cfg fun_name nargs nvars+    StackConv -> stackApply cfg fun_name nargs nvars++-- | Make specialized apply function with Stack calling convention+stackApply+  :: StgToJSConfig+  -> FastString+  -> Int+  -> Int+  -> JStat+stackApply s fun_name nargs nvars =+  -- special case for h$ap_0_0+  if nargs == 0 && nvars == 0+    then closure info0 body0+    else closure info body+  where+    info  = ClosureInfo (TxtI fun_name) (CIRegs 0 [PtrV]) fun_name (CILayoutUnknown nvars) CIStackFrame mempty+    info0 = ClosureInfo (TxtI fun_name) (CIRegs 0 [PtrV]) fun_name (CILayoutFixed 0 [])    CIStackFrame mempty++    body0 = adjSpN' 1 <> enter s r1++    body = jVar \c ->+             [ c |= closureEntry r1+             , traceRts s (toJExpr fun_name+                           + jString " "+                           + (c .^ "n")+                           + jString " sp: " + sp+                           + jString " a: "  + (c .^ "a"))+             , SwitchStat (entryClosureType c)+               [ (toJExpr Thunk, traceRts s (toJExpr $ fun_name <> ": thunk") <> profStat s pushRestoreCCS <> returnS c)+               , (toJExpr Fun, traceRts s (toJExpr $ fun_name <> ": fun") <> funCase c)+               , (toJExpr Pap, traceRts s (toJExpr $ fun_name <> ": pap") <> papCase c)+               , (toJExpr Blackhole, push' s [r1, var "h$return"] <> returnS (app "h$blockOnBlackhole" [r1]))+               ] (appS "throw" [toJExpr ("panic: " <> fun_name <> ", unexpected closure type: ") + (entryClosureType c)])+             ]++    funExact c = popSkip 1 (reverse $ take nvars jsRegsFromR2) <> returnS c+    stackArgs = map (\x -> stack .! (sp - toJExpr x)) [1..nvars]++    papCase :: JExpr -> JStat+    papCase c = jVar \expr arity0 arity ->+      case expr of+        ValExpr (JVar pap) -> [ arity0 |= papArity r1+                              , arity |= mask8 arity0+                              , traceRts s (toJExpr (fun_name <> ": found pap, arity: ") + arity)+                              , ifS (toJExpr nargs .===. arity)+                              --then+                                (traceRts s (toJExpr (fun_name <> ": exact")) <> funExact c)+                              -- else+                                (ifS (toJExpr nargs .>. arity)+                                  (traceRts s (toJExpr (fun_name <> ": oversat")) <> oversatCase c arity0 arity)+                                  (traceRts s (toJExpr (fun_name <> ": undersat"))+                                   <> mkPap s pap r1 (toJExpr nargs) stackArgs+                                   <> (sp |= sp - toJExpr (nvars + 1))+                                   <> (r1 |= toJExpr pap)+                                   <> returnStack))+                              ]+        _                   -> mempty+++    funCase :: JExpr -> JStat+    funCase c = jVar \expr ar0 ar ->+      case expr of+        ValExpr (JVar pap) -> [ ar0 |= funArity' c+                              , ar |= mask8 ar0+                              , ifS (toJExpr nargs .===. ar)+                                (traceRts s (toJExpr (fun_name <> ": exact")) <> funExact c)+                                (ifS (toJExpr nargs .>. ar)+                                 (traceRts s (toJExpr (fun_name <> ": oversat"))+                                  <> oversatCase c ar0 ar)+                                 (traceRts s (toJExpr (fun_name <> ": undersat"))+                                  <> mkPap s pap (toJExpr R1) (toJExpr nargs) stackArgs+                                  <> (sp |= sp - toJExpr (nvars+1))+                                  <> (r1 |= toJExpr pap)+                                  <> returnStack))+                              ]+        _                  -> mempty+++    -- oversat: call the function but keep enough on the stack for the next+    oversatCase :: JExpr -- function+                -> JExpr -- the arity tag+                -> JExpr -- real arity (arity & 0xff)+                -> JStat+    oversatCase c arity arity0 =+      jVar \rs newAp ->+        [ rs |= (arity .>>. 8)+        , loadRegs rs+        , sp |= sp - rs+        , newAp |= (var "h$apply" .! ((toJExpr nargs-arity0).|.((toJExpr nvars-rs).<<.8)))+        , stack .! sp |= newAp+        , profStat s pushRestoreCCS+        , traceRts s (toJExpr (fun_name <> ": new stack frame: ") + (newAp .^ "n"))+        , returnS c+        ]+      where+        loadRegs rs = SwitchStat rs switchAlts mempty+          where+            switchAlts = map (\x -> (toJExpr x, jsReg (x+1) |= stack .! (sp - toJExpr x))) [nvars,nvars-1..1]++-- | Make specialized apply function with Regs calling convention+--+-- h$ap_n_r_fast is entered if a function of unknown arity is called, n+-- arguments are already in r registers+fastApply :: StgToJSConfig -> FastString -> Int -> Int -> JStat+fastApply s fun_name nargs nvars = func ||= body0+  where+      -- special case for h$ap_0_0_fast+      body0 = if nargs == 0 && nvars == 0+        then jLam (enter s r1)+        else toJExpr (JFunc myFunArgs body)++      func    = TxtI fun_name++      myFunArgs = []++      regArgs = take nvars jsRegsFromR2++      mkAp :: Int -> Int -> [JExpr]+      mkAp n' r' = [ specApplyExpr (ApplySpec StackConv n' r') ]++      body =+        jVar \c farity arity ->+          [ c |= closureEntry r1+          , traceRts s (toJExpr (fun_name <> ": sp ") + sp)+          , SwitchStat (entryClosureType c)+             [(toJExpr Fun, traceRts s (toJExpr (fun_name <> ": ")+                                        + clName c+                                        + jString " (arity: " + (c .^ "a") + jString ")")+                            <> (farity |= funArity' c)+                            <> funCase c farity)+             ,(toJExpr Pap, traceRts s (toJExpr (fun_name <> ": pap")) <> (arity |= papArity r1) <> funCase c arity)+             ,(toJExpr Thunk, traceRts s (toJExpr (fun_name <> ": thunk")) <> push' s (reverse regArgs ++ mkAp nargs nvars) <> profStat s pushRestoreCCS <> returnS c)+             ,(toJExpr Blackhole, traceRts s (toJExpr (fun_name <> ": blackhole")) <> push' s (reverse regArgs ++ mkAp nargs nvars) <> push' s [r1, var "h$return"] <> returnS (app "h$blockOnBlackhole" [r1]))]+             (appS "throw" [toJExpr (fun_name <> ": unexpected closure type: ") + entryClosureType c])+          ]++      funCase :: JExpr -> JExpr -> JStat+      funCase c arity = jVar \arg ar -> case arg of+          ValExpr (JVar pap) -> [ ar |= mask8 arity+                                ,  ifS (toJExpr nargs .===. ar)+                                  -- then+                                  (traceRts s (toJExpr (fun_name <> ": exact")) <> returnS c)+                                  -- else+                                  (ifS (toJExpr nargs .>. ar)+                                    --then+                                    (traceRts s (toJExpr (fun_name <> ": oversat")) <> oversatCase c arity)+                                    -- else+                                    (traceRts s (toJExpr (fun_name <> ": undersat"))+                                     <> mkPap s pap r1 (toJExpr nargs) regArgs+                                     <> (r1 |= toJExpr pap)+                                     <> returnStack))+                                ]+          _             -> mempty++      oversatCase :: JExpr -> JExpr -> JStat+      oversatCase c arity =+         jVar \rs rsRemain ->+           [ rs |= arity .>>. 8+           , rsRemain |= toJExpr nvars - rs+           , traceRts s (toJExpr+                         (fun_name <> " regs oversat ")+                          + rs+                          + jString " remain: "+                          + rsRemain)+           , saveRegs rs+           , sp |= sp + rsRemain + 1+           , stack .! sp |= var "h$apply" .! ((rsRemain.<<.8).|. (toJExpr nargs - mask8 arity))+           , profStat s pushRestoreCCS+           , returnS c+           ]+          where+            saveRegs n = SwitchStat n switchAlts mempty+              where+                switchAlts = map (\x -> (toJExpr x, stack .! (sp + toJExpr (nvars-x)) |= jsReg (x+2))) [0..nvars-1]++zeroApply :: StgToJSConfig -> JStat+zeroApply s = mconcat+  [ TxtI "h$e" ||= jLam (\c -> (r1 |= c) <> enter s c)+  ]++-- carefully enter a closure that might be a thunk or a function++-- ex may be a local var, but must've been copied to R1 before calling this+enter :: StgToJSConfig -> JExpr -> JStat+enter s ex = jVar \c ->+  [ jwhenS (app "typeof" [ex] .!==. jTyObject) returnStack+  , c |= closureEntry ex+  , jwhenS (c .===. var "h$unbox_e") ((r1 |= closureField1 ex) <> returnStack)+  , SwitchStat (entryClosureType c)+    [ (toJExpr Con, mempty)+    , (toJExpr Fun, mempty)+    , (toJExpr Pap, returnStack)+    , (toJExpr Blackhole, push' s [var "h$ap_0_0", ex, var "h$return"]+        <> returnS (app "h$blockOnBlackhole" [ex]))+    ] (returnS c)+  ]++updates :: StgToJSConfig -> JStat+updates s = BlockStat+  [ closure+      (ClosureInfo (TxtI "h$upd_frame") (CIRegs 0 [PtrV]) "h$upd_frame" (CILayoutFixed 1 [PtrV]) CIStackFrame mempty)+      $ jVar \updatee waiters ss si sir ->+            let unbox_closure = Closure+                  { clEntry  = var "h$unbox_e"+                  , clField1 = sir+                  , clField2 = null_+                  , clMeta   = 0+                  , clCC     = Nothing+                  }+                updateCC updatee = closureCC updatee |= jCurrentCCS+            in [ updatee |= stack .! (sp - 1)+               , traceRts s (jString "h$upd_frame updatee alloc: " + updatee .^ "alloc")+               , -- wake up threads blocked on blackhole+                 waiters |= closureField2 updatee+               , jwhenS (waiters .!==. null_)+                           (loop 0 (.<. waiters .^ "length")+                              (\i -> appS "h$wakeupThread" [waiters .! i] <> postIncrS i))+               , -- update selectors+                 jwhenS ((app "typeof" [closureMeta updatee] .===. jTyObject) .&&. (closureMeta updatee .^ "sel"))+                 ((ss |= closureMeta updatee .^ "sel")+                   <> loop 0 (.<. ss .^ "length") \i -> mconcat+                        [ si |= ss .! i+                        , sir |= (closureField2 si) `ApplExpr` [r1]+                        , ifS (app "typeof" [sir] .===. jTyObject)+                            (copyClosure DontCopyCC si sir)+                            (assignClosure si unbox_closure)+                        , postIncrS i+                        ])+               , -- overwrite the object+                 ifS (app "typeof" [r1] .===. jTyObject)+                     (mconcat [ traceRts s (jString "$upd_frame: boxed: " + ((closureEntry r1) .^ "n"))+                              , copyClosure DontCopyCC updatee r1+                              ])+                     -- the heap object is represented by another type of value+                     -- (e.g. a JS number or string) so the unboxing closure+                     -- will simply return it.+                     (assignClosure updatee (unbox_closure { clField1 = r1 }))+               , profStat s (updateCC updatee)+               , adjSpN' 2+               , traceRts s (jString "h$upd_frame: updating: "+                             + updatee+                             + jString " -> "+                             + r1)+               , returnStack+               ]++   , closure+      (ClosureInfo (TxtI "h$upd_frame_lne") (CIRegs 0 [PtrV]) "h$upd_frame_lne" (CILayoutFixed 1 [PtrV]) CIStackFrame mempty)+      $ jVar \updateePos ->+          [ updateePos |= stack .! (sp - 1)+          , (stack .! updateePos |= r1)+          , adjSpN' 2+          , traceRts s (jString "h$upd_frame_lne: updating: "+                         + updateePos+                         + jString " -> "+                         + r1)+          , returnStack+          ]+  ]++selectors :: StgToJSConfig -> JStat+selectors s =+  mkSel "1"      closureField1+  <> mkSel "2a"  closureField2+  <> mkSel "2b"  (closureField1 . closureField2)+  <> mconcat (map mkSelN [3..16])+   where+    mkSelN :: Int -> JStat+    mkSelN x = mkSel (mkFastString $ show x)+                     (\e -> SelExpr (closureField2 (toJExpr e))+                            (TxtI $ mkFastString ("d" ++ show (x-1))))+++    mkSel :: FastString -> (JExpr -> JExpr) -> JStat+    mkSel name sel = mconcat+      [TxtI createName ||= jLam \r -> mconcat+          [ traceRts s (toJExpr ("selector create: " <> name <> " for ") + (r .^ "alloc"))+          , ifS (isThunk r .||. isBlackhole r)+              (returnS (app "h$mkSelThunk" [r, toJExpr (v entryName), toJExpr (v resName)]))+              (returnS (sel r))+          ]+      , TxtI resName ||= jLam \r -> mconcat+          [ traceRts s (toJExpr ("selector result: " <> name <> " for ") + (r .^ "alloc"))+          , returnS (sel r)+          ]+      , closure+        (ClosureInfo (TxtI entryName) (CIRegs 0 [PtrV]) ("select " <> name) (CILayoutFixed 1 [PtrV]) CIThunk mempty)+        (jVar \tgt ->+          [ tgt |= closureField1 r1+          , traceRts s (toJExpr ("selector entry: " <> name <> " for ") + (tgt .^ "alloc"))+          , ifS (isThunk tgt .||. isBlackhole tgt)+              (preIncrS sp+               <> (stack .! sp |= var frameName)+               <> returnS (app "h$e" [tgt]))+              (returnS (app "h$e" [sel tgt]))+          ])+      , closure+        (ClosureInfo (TxtI frameName) (CIRegs 0 [PtrV]) ("select " <> name <> " frame") (CILayoutFixed 0 []) CIStackFrame mempty)+        $ mconcat [ traceRts s (toJExpr ("selector frame: " <> name))+                  , postDecrS sp+                  , returnS (app "h$e" [sel r1])+                  ]+      ]++      where+         v x   = JVar (TxtI x)+         n ext =  "h$c_sel_" <> name <> ext+         createName = n ""+         resName    = n "_res"+         entryName  = n "_e"+         frameName  = n "_frame_e"+++-- arity is the remaining arity after our supplied arguments are applied+mkPap :: StgToJSConfig+      -> Ident   -- ^ id of the pap object+      -> JExpr   -- ^ the function that's called (can be a second pap)+      -> JExpr   -- ^ number of arguments in pap+      -> [JExpr] -- ^ values for the supplied arguments+      -> JStat+mkPap s tgt fun n values =+      traceRts s (toJExpr $ "making pap with: " ++ show (length values) ++ " items")+      `mappend`+      allocDynamic s True tgt (toJExpr entry) (fun:papAr:map toJExpr values')+        (if csProf s then Just jCurrentCCS else Nothing)+  where+    papAr = funOrPapArity fun Nothing - toJExpr (length values * 256) - n++    values' | GHC.Prelude.null values = [null_]+            | otherwise   = values+    entry | length values > numSpecPap = TxtI "h$pap_gen"+          | otherwise                  = specPapIdents ! length values++-- | Number of specialized PAPs (pre-generated for a given number of args)+numSpecPap :: Int+numSpecPap = 6++-- specialized (faster) pap generated for [0..numSpecPap]+-- others use h$pap_gen+specPap :: [Int]+specPap = [0..numSpecPap]++-- | Cache of specialized PAP idents+specPapIdents :: Array Int Ident+specPapIdents = listArray (0,numSpecPap) $ map (TxtI . mkFastString . ("h$pap_"++) . show) specPap++pap :: StgToJSConfig+    -> Int+    -> JStat+pap s r = closure (ClosureInfo funcIdent CIRegsUnknown funcName (CILayoutUnknown (r+2)) CIPap mempty) body+  where+    funcIdent = TxtI funcName+    funcName = mkFastString ("h$pap_" ++ show r)++    body = jVar \c d f extra ->+             [ c |= closureField1 r1+             , d |= closureField2 r1+             , f |= closureEntry  c+             , assertRts s (isFun' f .||. isPap' f) (funcName <> ": expected function or pap")+             , profStat s (enterCostCentreFun currentCCS)+             , extra |= (funOrPapArity c (Just f) .>>. 8) - toJExpr r+             , traceRts s (toJExpr (funcName <> ": pap extra args moving: ") + extra)+             , moveBy extra+             , loadOwnArgs d+             , r1 |= c+             , returnS f+             ]+    moveBy extra = SwitchStat extra+                   (reverse $ map moveCase [1..maxReg-r-1]) mempty+    moveCase m = (toJExpr m, jsReg (m+r+1) |= jsReg (m+1))+    loadOwnArgs d = mconcat $ map (\r ->+        jsReg (r+1) |= dField d (r+2)) [1..r]+    dField d n = SelExpr d (TxtI . mkFastString $ ('d':show (n-1)))++-- Construct a generic PAP+papGen :: StgToJSConfig -> JStat+papGen cfg =+   closure (ClosureInfo funcIdent CIRegsUnknown funcName CILayoutVariable CIPap mempty)+           (jVar \c f d pr or r ->+              [ c |= closureField1 r1+              , d |= closureField2 r1+              , f |= closureEntry  c+              , pr |= funOrPapArity c (Just f) .>>. 8+              , or |= papArity r1 .>>. 8+              , r |= pr - or+              , assertRts cfg+                (isFun' f .||. isPap' f)+                (jString "h$pap_gen: expected function or pap")+              , profStat cfg (enterCostCentreFun currentCCS)+              , traceRts cfg (jString "h$pap_gen: generic pap extra args moving: " + or)+              , appS "h$moveRegs2" [or, r]+              , loadOwnArgs d r+              , r1 |= c+              , returnS f+              ])+++  where+    funcIdent = TxtI funcName+    funcName = "h$pap_gen"+    loadOwnArgs d r =+      let prop n = d .^ ("d" <> mkFastString (show $ n+1))+          loadOwnArg n = (toJExpr n, jsReg (n+1) |= prop n)+      in  SwitchStat r (map loadOwnArg [127,126..1]) mempty++-- general utilities+-- move the first n registers, starting at R2, m places up (do not use with negative m)+moveRegs2 :: JStat+moveRegs2 = TxtI "h$moveRegs2" ||= jLam moveSwitch+  where+    moveSwitch n m = SwitchStat ((n .<<. 8) .|. m) switchCases (defaultCase n m)+    -- fast cases+    switchCases = [switchCase n m | n <- [1..5], m <- [1..4]]+    switchCase :: Int -> Int -> (JExpr, JStat)+    switchCase n m = (toJExpr $+                      (n `Bits.shiftL` 8) Bits..|. m+                     , mconcat (map (`moveRegFast` m) [n+1,n..2])+                       <> BreakStat Nothing {-[j| break; |]-})+    moveRegFast n m = jsReg (n+m) |= jsReg n+    -- fallback+    defaultCase n m =+      loop n (.>.0) (\i -> appS "h$setReg" [i+1+m, app "h$getReg" [i+1]] `mappend` postDecrS i)+++-- Initalize a variable sized object from an array of values+initClosure :: StgToJSConfig -> JExpr -> JExpr -> JExpr -> JExpr+initClosure cfg entry values ccs = app "h$init_closure"+  [ newClosure $ Closure+      { clEntry  = entry+      , clField1 = null_+      , clField2 = null_+      , clMeta   = 0+      , clCC     = if csProf cfg then Just ccs else Nothing+      }+  , values+  ]++-- | Return an expression for every field of the given Id+getIdFields :: Id -> G [TypedExpr]+getIdFields i = assocIdExprs i <$> varsForId i++-- | Store fields of Id into the given target expressions+storeIdFields :: Id -> [TypedExpr] -> G JStat+storeIdFields i dst = do+  fields <- getIdFields i+  pure (assignCoerce1 dst fields)
+ compiler/GHC/StgToJS/Arg.hs view
@@ -0,0 +1,285 @@+{-# LANGUAGE LambdaCase #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Args+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+--  Code generation of application arguments+-----------------------------------------------------------------------------++module GHC.StgToJS.Arg+  ( genArg+  , genIdArg+  , genIdArgI+  , genIdStackArgI+  , allocConStatic+  , allocUnboxedConStatic+  , allocateStaticList+  , jsStaticArg+  , jsStaticArgs+  )+where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Make++import GHC.StgToJS.DataCon+import GHC.StgToJS.Types+import GHC.StgToJS.Monad+import GHC.StgToJS.Literal+import GHC.StgToJS.CoreUtils+import GHC.StgToJS.Profiling+import GHC.StgToJS.Ids++import GHC.Builtin.Types+import GHC.Stg.Syntax+import GHC.Core.DataCon++import GHC.Types.CostCentre+import GHC.Types.Unique.FM+import GHC.Types.Id++import GHC.Utils.Misc+import GHC.Utils.Outputable+import GHC.Utils.Panic+import qualified Control.Monad.Trans.State.Strict as State++{-+Note [ Unboxable Literals Optimization ]+~~~~~~~~~~~~~~~~~~++Boxable types in the JS backend are represented as heap objects. See Note+[StgToJS design] in GHC.StgToJS.hs for more details. Some types, such as Int8+do not benefit from not being wrapped in an object in the JS runtime. This optimization+detects such types and changes the code generator to generate a more efficient+representation. The change is minor and saves one level on indirection. Instead+of generating a wrapper object with a field for the value's payload, such as:++// a JS object for an Int8+var anInt8 = { d1 = <Int8# payload>+             , f  : entry function which would scrutinize the payload+             }++we instead generate:++// notice, no wrapper object. This representation is essentially an Int8# in the JS backend+var anInt8 = <Int8# payload>++This optimization fires when the follow invariants hold:+  1. The value in question has a Type which has a single data constructor+  2. The data constructor holds a single field that is monomorphic+  3. The value in question is distinguishable from a THUNK using the JavaScript typeof operator.++From the haskell perspective this means that:+  1. An Int8# is always a JavaScript 'number', never a JavaScript object.+  2. An Int8 is either a JavaScript 'number' _or_ a JavaScript object depending on+     its use case and this optimization.++How is this sound?+~~~~~~~~~~~~~~~~~~++Normally this optimization would violate the guarantees of call-by-need, however+we are able to statically detect whether the type in question will be a THUNK or+not during code gen because the JS backend is consuming STG and we can check+during runtime with the typeof operator. Similarly we can check at runtime using+JavaScript's introspection operator `typeof`. Thus, when we know the value in+question will not be a THUNK we can safely elide the wrapping object, which+unboxes the value in the JS runtime. For example, an Int8 contains an Int8#+which has the JavaScript type 'number'. A THUNK of type Int8 would have a+JavaScript type 'object', so using 'typeof' allows us to check if we have+something that is definitely evaluated (i.e., a 'number') or something else. If+it is an 'object' then we may need to enter it to begin its evaluation. Consider+a type which has a 'ThreadId#' field; such as type would not be subject to this+optimization because it has to be represented as a JavaScript 'object' and thus+cannot be unboxed in this way. Another (edge) case is Int64#. Int64# is+similarly not unboxable in this way because Int64# does not fit in one+JavaScript variable and thus requires an 'object' for its representation in the+JavaScript runtime.++-}++-- | Generate JS code for static arguments+genStaticArg :: HasDebugCallStack => StgArg -> G [StaticArg]+genStaticArg a = case a of+  StgLitArg l -> map StaticLitArg <$> genStaticLit l+  StgVarArg i -> do+    unFloat <- State.gets gsUnfloated+    case lookupUFM unFloat i of+      Nothing -> reg+      Just expr -> unfloated expr+     where+       r = uTypeVt . stgArgType $ a+       reg+         | isVoid r            =+             return []+         | i == trueDataConId  =+             return [StaticLitArg (BoolLit True)]+         | i == falseDataConId =+             return [StaticLitArg (BoolLit False)]+         | isMultiVar r        =+             map (\(TxtI t) -> StaticObjArg t) <$> mapM (identForIdN i) [1..varSize r] -- this seems wrong, not an obj?+         | otherwise           = (\(TxtI it) -> [StaticObjArg it]) <$> identForId i++       unfloated :: CgStgExpr -> G [StaticArg]+       unfloated (StgLit l) = map StaticLitArg <$> genStaticLit l+       unfloated (StgConApp dc _n args _)+         | isBoolDataCon dc || isUnboxableCon dc =+             (:[]) . allocUnboxedConStatic dc . concat <$> mapM genStaticArg args -- fixme what is allocunboxedcon?+         | null args = (\(TxtI t) -> [StaticObjArg t]) <$> identForId (dataConWorkId dc)+         | otherwise = do+             as       <- concat <$> mapM genStaticArg args+             (TxtI e) <- identForDataConWorker dc+             return [StaticConArg e as]+       unfloated x = pprPanic "genArg: unexpected unfloated expression" (pprStgExpr panicStgPprOpts x)++-- | Generate JS code for an StgArg+genArg :: HasDebugCallStack => StgArg -> G [JExpr]+genArg a = case a of+  StgLitArg l -> genLit l+  StgVarArg i -> do+    unFloat <- State.gets gsUnfloated+    case lookupUFM unFloat i of+      Just expr -> unfloated expr+      Nothing+       | isVoid r            -> return []+       | i == trueDataConId  -> return [true_]+       | i == falseDataConId -> return [false_]+       | isMultiVar r        -> mapM (varForIdN i) [1..varSize r]+       | otherwise           -> (:[]) <$> varForId i++   where+     -- if our argument is a joinid, it can be an unboxed tuple+     r :: HasDebugCallStack => VarType+     r = uTypeVt . stgArgType $ a++     unfloated :: HasDebugCallStack => CgStgExpr -> G [JExpr]+     unfloated = \case+      StgLit l -> genLit l+      StgConApp dc _n args _+       | isBoolDataCon dc || isUnboxableCon dc+       -> (:[]) . allocUnboxedCon dc . concat <$> mapM genArg args+       | null args -> (:[]) <$> varForId (dataConWorkId dc)+       | otherwise -> do+           as <- concat <$> mapM genArg args+           e  <- varForDataConWorker dc+           inl_alloc <- csInlineAlloc <$> getSettings+           return [allocDynamicE inl_alloc e as Nothing]+      x -> pprPanic "genArg: unexpected unfloated expression" (pprStgExpr panicStgPprOpts x)++-- | Generate a Var as JExpr+genIdArg :: HasDebugCallStack => Id -> G [JExpr]+genIdArg i = genArg (StgVarArg i)++-- | Generate an Id as an Ident+genIdArgI :: HasDebugCallStack => Id -> G [Ident]+genIdArgI i+  | isVoid r     = return []+  | isMultiVar r = mapM (identForIdN i) [1..varSize r]+  | otherwise    = (:[]) <$> identForId i+  where+    r = uTypeVt . idType $ i++-- | Generate IDs for stack arguments. See 'StgToJS.Expr.loadRetArgs' for use case+genIdStackArgI :: HasDebugCallStack => Id -> G [(Ident,StackSlot)]+genIdStackArgI i = zipWith f [1..] <$> genIdArgI i+  where+    f :: Int -> Ident -> (Ident,StackSlot)+    f n ident = (ident, SlotId i n)++-- | Allocate Static Constructors+allocConStatic :: HasDebugCallStack => Ident -> CostCentreStack -> DataCon -> [StgArg] -> G ()+allocConStatic (TxtI to) cc con args = do+  as <- mapM genStaticArg args+  cc' <- costCentreStackLbl cc+  allocConStatic' cc' (concat as)+  where+    -- see Note [ Unboxable Literals Optimization ] for the purpose of these+    -- checks+    allocConStatic' :: HasDebugCallStack => Maybe Ident -> [StaticArg] -> G ()+    allocConStatic' cc' []+      | isBoolDataCon con && dataConTag con == 1 =+           emitStatic to (StaticUnboxed $ StaticUnboxedBool False) cc'+      | isBoolDataCon con && dataConTag con == 2 =+           emitStatic to (StaticUnboxed $ StaticUnboxedBool True) cc'+      | otherwise = do+           (TxtI e) <- identForDataConWorker con+           emitStatic to (StaticData e []) cc'+    allocConStatic' cc' [x]+      | isUnboxableCon con =+        case x of+          StaticLitArg (IntLit i)    ->+            emitStatic to (StaticUnboxed $ StaticUnboxedInt i) cc'+          StaticLitArg (BoolLit b)   ->+            emitStatic to (StaticUnboxed $ StaticUnboxedBool b) cc'+          StaticLitArg (DoubleLit d) ->+            emitStatic to (StaticUnboxed $ StaticUnboxedDouble d) cc'+          _                          ->+            pprPanic "allocConStatic: invalid unboxed literal" (ppr x)+    allocConStatic' cc' xs =+           if con == consDataCon+              then case args of+                (a0:a1:_) -> flip (emitStatic to) cc' =<< allocateStaticList [a0] a1+                _         -> panic "allocConStatic: invalid args for consDataCon"+              else do+                (TxtI e) <- identForDataConWorker con+                emitStatic to (StaticData e xs) cc'++-- | Allocate unboxed constructors+allocUnboxedConStatic :: DataCon -> [StaticArg] -> StaticArg+allocUnboxedConStatic con = \case+  []+    | isBoolDataCon con && dataConTag con == 1+    -> StaticLitArg (BoolLit False)+    | isBoolDataCon con && dataConTag con == 2+    -> StaticLitArg (BoolLit True)+  [a@(StaticLitArg (IntLit _i))]    -> a+  [a@(StaticLitArg (DoubleLit _d))] -> a+  _ -> pprPanic "allocUnboxedConStatic: not an unboxed constructor" (ppr con)+++-- | Allocate Static list+allocateStaticList :: [StgArg] -> StgArg -> G StaticVal+allocateStaticList xs a@(StgVarArg i)+  | isDataConId_maybe i == Just nilDataCon = listAlloc xs Nothing+  | otherwise = do+      unFloat <- State.gets gsUnfloated+      case lookupUFM unFloat i of+        Just (StgConApp dc _n [h,t] _)+          | dc == consDataCon -> allocateStaticList (h:xs) t+        _ -> listAlloc xs (Just a)+  where+    listAlloc :: [StgArg] -> Maybe StgArg -> G StaticVal+    listAlloc xs Nothing  = do+      as <- concat . reverse <$> mapM genStaticArg xs+      return (StaticList as Nothing)+    listAlloc xs (Just r) = do+      as <- concat . reverse <$> mapM genStaticArg xs+      r' <- genStaticArg r+      case r' of+        [StaticObjArg ri] -> return (StaticList as (Just ri))+        _                 ->+          pprPanic "allocateStaticList: invalid argument (tail)" (ppr (xs, r))+allocateStaticList _ _ = panic "allocateStaticList: unexpected literal in list"++-- | Generate JS code corresponding to a static arg+jsStaticArg :: StaticArg -> JExpr+jsStaticArg = \case+  StaticLitArg l      -> toJExpr l+  StaticObjArg t      -> ValExpr (JVar (TxtI t))+  StaticConArg c args ->+    allocDynamicE False (ValExpr . JVar . TxtI $ c) (map jsStaticArg args) Nothing++-- | Generate JS code corresponding to a list of static args+jsStaticArgs :: [StaticArg] -> JExpr+jsStaticArgs = ValExpr . JList . map jsStaticArg+
+ compiler/GHC/StgToJS/Closure.hs view
@@ -0,0 +1,156 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module GHC.StgToJS.Closure+  ( closureInfoStat+  , closure+  , conClosure+  , Closure (..)+  , newClosure+  , assignClosure+  , CopyCC (..)+  , copyClosure+  )+where++import GHC.Prelude+import GHC.Data.FastString++import GHC.StgToJS.Heap+import GHC.StgToJS.Types+import GHC.StgToJS.CoreUtils+import GHC.StgToJS.Regs (stack,sp)++import GHC.JS.Make+import GHC.JS.Syntax++import Data.Monoid+import qualified Data.Bits as Bits++closureInfoStat :: Bool -> ClosureInfo -> JStat+closureInfoStat debug (ClosureInfo obj rs name layout ctype srefs)+  = setObjInfoL debug obj rs layout ty name tag srefs+      where+        !ty = case ctype of+          CIThunk      -> Thunk+          CIFun {}     -> Fun+          CICon {}     -> Con+          CIBlackhole  -> Blackhole+          CIPap        -> Pap+          CIStackFrame -> StackFrame+        !tag = case ctype of+          CIThunk           -> 0+          CIFun arity nregs -> mkArityTag arity nregs+          CICon con         -> con+          CIBlackhole       -> 0+          CIPap             -> 0+          CIStackFrame      -> 0+++setObjInfoL :: Bool        -- ^ debug: output symbol names+            -> Ident       -- ^ the object name+            -> CIRegs      -- ^ things in registers+            -> CILayout    -- ^ layout of the object+            -> ClosureType -- ^ closure type+            -> FastString  -- ^ object name, for printing+            -> Int         -- ^ `a' argument, depends on type (arity, conid)+            -> CIStatic    -- ^ static refs+            -> JStat+setObjInfoL debug obj rs layout t n a+  = setObjInfo debug obj t n field_types a size rs+      where+        size = case layout of+          CILayoutVariable   -> (-1)+          CILayoutUnknown sz -> sz+          CILayoutFixed sz _ -> sz+        field_types = case layout of+          CILayoutVariable     -> []+          CILayoutUnknown size -> toTypeList (replicate size ObjV)+          CILayoutFixed _ fs   -> toTypeList fs++setObjInfo :: Bool        -- ^ debug: output all symbol names+           -> Ident       -- ^ the thing to modify+           -> ClosureType -- ^ closure type+           -> FastString  -- ^ object name, for printing+           -> [Int]       -- ^ list of item types in the object, if known (free variables, datacon fields)+           -> Int         -- ^ extra 'a' parameter, for constructor tag or arity+           -> Int         -- ^ object size, -1 (number of vars) for unknown+           -> CIRegs      -- ^ things in registers+           -> CIStatic    -- ^ static refs+           -> JStat+setObjInfo debug obj t name fields a size regs static+   | debug     = appS "h$setObjInfo" [ toJExpr obj+                                     , toJExpr t+                                     , toJExpr name+                                     , toJExpr fields+                                     , toJExpr a+                                     , toJExpr size+                                     , toJExpr (regTag regs)+                                     , toJExpr static+                                     ]+   | otherwise = appS "h$o" [ toJExpr obj+                            , toJExpr t+                            , toJExpr a+                            , toJExpr size+                            , toJExpr (regTag regs)+                            , toJExpr static+                            ]+  where+    regTag CIRegsUnknown       = -1+    regTag (CIRegs skip types) =+      let nregs = sum $ map varSize types+      in  skip + (nregs `Bits.shiftL` 8)++closure :: ClosureInfo -- ^ object being info'd see @ciVar@ in @ClosureInfo@+        -> JStat       -- ^ rhs+        -> JStat+closure ci body = (ciVar ci ||= jLam body) `mappend` closureInfoStat False ci++conClosure :: Ident -> FastString -> CILayout -> Int -> JStat+conClosure symbol name layout constr =+  closure (ClosureInfo symbol (CIRegs 0 [PtrV]) name layout (CICon constr) mempty)+          (returnS (stack .! sp))++-- | Used to pass arguments to newClosure with some safety+data Closure = Closure+  { clEntry  :: JExpr+  , clField1 :: JExpr+  , clField2 :: JExpr+  , clMeta   :: JExpr+  , clCC     :: Maybe JExpr+  }++newClosure :: Closure -> JExpr+newClosure Closure{..} =+  let xs = [ (closureEntry_ , clEntry)+           , (closureField1_, clField1)+           , (closureField2_, clField2)+           , (closureMeta_  , clMeta)+           ]+  in case clCC of+    -- CC field is optional (probably to minimize code size as we could assign+    -- null_, but we get the same effect implicitly)+    Nothing -> ValExpr (jhFromList xs)+    Just cc -> ValExpr (jhFromList $ (closureCC_,cc) : xs)++assignClosure :: JExpr -> Closure -> JStat+assignClosure t Closure{..} = BlockStat+  [ closureEntry  t |= clEntry+  , closureField1 t |= clField1+  , closureField2 t |= clField2+  , closureMeta   t |= clMeta+  ] <> case clCC of+      Nothing -> mempty+      Just cc -> closureCC t |= cc++data CopyCC = CopyCC | DontCopyCC++copyClosure :: CopyCC -> JExpr -> JExpr -> JStat+copyClosure copy_cc t s = BlockStat+  [ closureEntry  t |= closureEntry  s+  , closureField1 t |= closureField1 s+  , closureField2 t |= closureField2 s+  , closureMeta   t |= closureMeta   s+  ] <> case copy_cc of+      DontCopyCC -> mempty+      CopyCC     -> closureCC t |= closureCC s
+ compiler/GHC/StgToJS/CodeGen.hs view
@@ -0,0 +1,367 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE LambdaCase #-}++-- | JavaScript code generator+module GHC.StgToJS.CodeGen+  ( stgToJS+  )+where++import GHC.Prelude++import GHC.Driver.Flags (DumpFlag (Opt_D_dump_js))++import GHC.JS.Ppr+import GHC.JS.Syntax+import GHC.JS.Make+import GHC.JS.Transform++import GHC.StgToJS.Arg+import GHC.StgToJS.Sinker+import GHC.StgToJS.Types+import qualified GHC.StgToJS.Object as Object+import GHC.StgToJS.StgUtils+import GHC.StgToJS.CoreUtils+import GHC.StgToJS.Deps+import GHC.StgToJS.Expr+import GHC.StgToJS.ExprCtx+import GHC.StgToJS.Monad+import GHC.StgToJS.Profiling+import GHC.StgToJS.Regs+import GHC.StgToJS.StaticPtr+import GHC.StgToJS.Symbols+import GHC.StgToJS.Stack+import GHC.StgToJS.Ids++import GHC.Stg.Syntax+import GHC.Core.DataCon+import GHC.Core.TyCo.Rep (scaledThing)++import GHC.Unit.Module+import GHC.Linker.Types (SptEntry (..))++import GHC.Types.CostCentre+import GHC.Types.ForeignStubs (ForeignStubs (..), getCHeader, getCStub)+import GHC.Types.RepType+import GHC.Types.Id+import GHC.Types.Unique++import GHC.Data.FastString+import GHC.Utils.Encoding+import GHC.Utils.Logger+import GHC.Utils.Panic+import GHC.Utils.Misc+import GHC.Utils.Binary+import qualified Control.Monad.Trans.State.Strict as State+import GHC.Utils.Outputable hiding ((<>))++import qualified Data.Set as S+import Data.Monoid+import Control.Monad+import System.Directory+import System.FilePath++-- | Code generator for JavaScript+stgToJS+  :: Logger+  -> StgToJSConfig+  -> [CgStgTopBinding]+  -> Module+  -> [SptEntry]+  -> ForeignStubs+  -> CollectedCCs+  -> FilePath -- ^ Output file name+  -> IO ()+stgToJS logger config stg_binds0 this_mod spt_entries foreign_stubs cccs output_fn = do++  let (unfloated_binds, stg_binds) = sinkPgm this_mod stg_binds0+    -- TODO: avoid top level lifting in core-2-core when the JS backend is+    -- enabled instead of undoing it here++    -- TODO: add dump pass for optimized STG ast for JS++  (deps,lus) <- runG config this_mod unfloated_binds $ do+    ifProfilingM $ initCostCentres cccs+    lus  <- genUnits this_mod stg_binds spt_entries foreign_stubs+    deps <- genDependencyData this_mod lus+    pure (deps,lus)++  -- Doc to dump when -ddump-js is enabled+  when (logHasDumpFlag logger Opt_D_dump_js) $ do+    putDumpFileMaybe logger Opt_D_dump_js "JavaScript code" FormatJS+      $ vcat (fmap (docToSDoc . jsToDoc . oiStat . luObjUnit) lus)++  -- Write the object file+  bh <- openBinMem (4 * 1024 * 1000) -- a bit less than 4kB+  Object.putObject bh (moduleName this_mod) deps (map luObjUnit lus)++  createDirectoryIfMissing True (takeDirectory output_fn)+  writeBinMem bh output_fn++++-- | Generate the ingredients for the linkable units for this module+genUnits :: HasDebugCallStack+         => Module+         -> [CgStgTopBinding]+         -> [SptEntry]+         -> ForeignStubs+         -> G [LinkableUnit] -- ^ the linkable units+genUnits m ss spt_entries foreign_stubs = do+    gbl     <- generateGlobalBlock+    exports <- generateExportsBlock+    others  <- go 2 ss+    pure (gbl:exports:others)+    where+      go :: HasDebugCallStack+         => Int                 -- the block we're generating (block 0 is the global unit for the module)+         -> [CgStgTopBinding]+         -> G [LinkableUnit]+      go !n = \case+        []     -> pure []+        (x:xs) -> do+          mlu <- generateBlock x n+          lus <- go (n+1) xs+          return (maybe lus (:lus) mlu)++      --   Generate the global unit that all other blocks in the module depend on+      --   used for cost centres and static initializers+      --   the global unit has no dependencies, exports the moduleGlobalSymbol+      generateGlobalBlock :: HasDebugCallStack => G LinkableUnit+      generateGlobalBlock = do+        glbl <- State.gets gsGlobal+        staticInit <-+          initStaticPtrs spt_entries+        let stat = ( -- O.optimize .+                     jsSaturate (Just $ modulePrefix m 1)+                   $ mconcat (reverse glbl) <> staticInit)+        let syms = [moduleGlobalSymbol m]+        let oi = ObjUnit+                  { oiSymbols  = syms+                  , oiClInfo   = []+                  , oiStatic   = []+                  , oiStat     = stat+                  , oiRaw      = mempty+                  , oiFExports = []+                  , oiFImports = []+                  }+        let lu = LinkableUnit+                  { luObjUnit      = oi+                  , luIdExports    = []+                  , luOtherExports = syms+                  , luIdDeps       = []+                  , luPseudoIdDeps = []+                  , luOtherDeps    = []+                  , luRequired     = False+                  , luForeignRefs  = []+                  }+        pure lu++      generateExportsBlock :: HasDebugCallStack => G LinkableUnit+      generateExportsBlock = do+        let (f_hdr, f_c) = case foreign_stubs of+                                  NoStubs            -> (empty, empty)+                                  ForeignStubs hdr c -> (getCHeader hdr, getCStub c)+            unique_deps = map mkUniqueDep (lines $ renderWithContext defaultSDocContext f_hdr)+            mkUniqueDep (tag:xs) = mkUnique tag (read xs)+            mkUniqueDep []       = panic "mkUniqueDep"++        let syms = [moduleExportsSymbol m]+        let raw  = utf8EncodeByteString $ renderWithContext defaultSDocContext f_c+        let oi = ObjUnit+                  { oiSymbols  = syms+                  , oiClInfo   = []+                  , oiStatic   = []+                  , oiStat     = mempty+                  , oiRaw      = raw+                  , oiFExports = []+                  , oiFImports = []+                  }+        let lu = LinkableUnit+                  { luObjUnit      = oi+                  , luIdExports    = []+                  , luOtherExports = syms+                  , luIdDeps       = []+                  , luPseudoIdDeps = unique_deps+                  , luOtherDeps    = []+                  , luRequired     = True+                  , luForeignRefs  = []+                  }+        pure lu++      --   Generate the linkable unit for one binding or group of+      --   mutually recursive bindings+      generateBlock :: HasDebugCallStack+                    => CgStgTopBinding+                    -> Int+                    -> G (Maybe LinkableUnit)+      generateBlock top_bind n = case top_bind of+        StgTopStringLit bnd str -> do+          bids <- identsForId bnd+          case bids of+            [(TxtI b1t),(TxtI b2t)] -> do+              -- [e1,e2] <- genLit (MachStr str)+              emitStatic b1t (StaticUnboxed (StaticUnboxedString str)) Nothing+              emitStatic b2t (StaticUnboxed (StaticUnboxedStringOffset str)) Nothing+              _extraTl   <- State.gets (ggsToplevelStats . gsGroup)+              si        <- State.gets (ggsStatic . gsGroup)+              let body = mempty -- mconcat (reverse extraTl) <> b1 ||= e1 <> b2 ||= e2+              let stat = jsSaturate (Just $ modulePrefix m n) body+              let ids = [bnd]+              syms <- (\(TxtI i) -> [i]) <$> identForId bnd+              let oi = ObjUnit+                        { oiSymbols  = syms+                        , oiClInfo   = []+                        , oiStatic   = si+                        , oiStat     = stat+                        , oiRaw      = ""+                        , oiFExports = []+                        , oiFImports = []+                        }+              let lu = LinkableUnit+                        { luObjUnit      = oi+                        , luIdExports    = ids+                        , luOtherExports = []+                        , luIdDeps       = []+                        , luPseudoIdDeps = []+                        , luOtherDeps    = []+                        , luRequired     = False+                        , luForeignRefs  = []+                        }+              pure (Just lu)+            _ -> panic "generateBlock: invalid size"++        StgTopLifted decl -> do+          tl        <- genToplevel decl+          extraTl   <- State.gets (ggsToplevelStats . gsGroup)+          ci        <- State.gets (ggsClosureInfo . gsGroup)+          si        <- State.gets (ggsStatic . gsGroup)+          unf       <- State.gets gsUnfloated+          extraDeps <- State.gets (ggsExtraDeps . gsGroup)+          fRefs     <- State.gets (ggsForeignRefs . gsGroup)+          resetGroup+          let allDeps  = collectIds unf decl+              topDeps  = collectTopIds decl+              required = hasExport decl+              stat     = -- Opt.optimize .+                         jsSaturate (Just $ modulePrefix m n)+                       $ mconcat (reverse extraTl) <> tl+          syms <- mapM (fmap (\(TxtI i) -> i) . identForId) topDeps+          let oi = ObjUnit+                    { oiSymbols  = syms+                    , oiClInfo   = ci+                    , oiStatic   = si+                    , oiStat     = stat+                    , oiRaw      = ""+                    , oiFExports = []+                    , oiFImports = fRefs+                    }+          let lu = LinkableUnit+                    { luObjUnit      = oi+                    , luIdExports    = topDeps+                    , luOtherExports = []+                    , luIdDeps       = allDeps+                    , luPseudoIdDeps = []+                    , luOtherDeps    = S.toList extraDeps+                    , luRequired     = required+                    , luForeignRefs  = fRefs+                    }+          pure $! seqList topDeps `seq` seqList allDeps `seq` Just lu++-- | variable prefix for the nth block in module+modulePrefix :: Module -> Int -> FastString+modulePrefix m n =+  let encMod = zEncodeString . moduleNameString . moduleName $ m+  in  mkFastString $ "h$" ++ encMod ++ "_id_" ++ show n++genToplevel :: CgStgBinding -> G JStat+genToplevel (StgNonRec bndr rhs) = genToplevelDecl bndr rhs+genToplevel (StgRec bs)          =+  mconcat <$> mapM (\(bndr, rhs) -> genToplevelDecl bndr rhs) bs++genToplevelDecl :: Id -> CgStgRhs -> G JStat+genToplevelDecl i rhs = do+  s1 <- resetSlots (genToplevelConEntry i rhs)+  s2 <- resetSlots (genToplevelRhs i rhs)+  return (s1 <> s2)++genToplevelConEntry :: Id -> CgStgRhs -> G JStat+genToplevelConEntry i rhs = case rhs of+   StgRhsCon _cc con _mu _ts _args+     | isDataConWorkId i+       -> genSetConInfo i con (stgRhsLive rhs) -- NoSRT+   StgRhsClosure _ _cc _upd_flag _args _body+     | Just dc <- isDataConWorkId_maybe i+       -> genSetConInfo i dc (stgRhsLive rhs) -- srt+   _ -> pure mempty++genSetConInfo :: HasDebugCallStack => Id -> DataCon -> LiveVars -> G JStat+genSetConInfo i d l {- srt -} = do+  ei <- identForDataConEntryId i+  sr <- genStaticRefs l+  emitClosureInfo $ ClosureInfo ei+                                (CIRegs 0 [PtrV])+                                (mkFastString $ renderWithContext defaultSDocContext (ppr d))+                                (fixedLayout $ map uTypeVt fields)+                                (CICon $ dataConTag d)+                                sr+  return (ei ||= mkDataEntry)+    where+      -- dataConRepArgTys sometimes returns unboxed tuples. is that a bug?+      fields = concatMap (map primRepToType . typePrimRep . unwrapType . scaledThing)+                         (dataConRepArgTys d)+        -- concatMap (map slotTyToType . repTypeSlots . repType) (dataConRepArgTys d)++mkDataEntry :: JExpr+mkDataEntry = ValExpr $ JFunc [] returnStack++genToplevelRhs :: Id -> CgStgRhs -> G JStat+-- general cases:+genToplevelRhs i rhs = case rhs of+  StgRhsCon cc con _mu _tys args -> do+    ii <- identForId i+    allocConStatic ii cc con args+    return mempty+  StgRhsClosure _ext cc _upd_flag {- srt -} args body -> do+    {-+      algorithm:+       - collect all Id refs that are in the global id cache+       - count usage in body for each ref+       - order by increasing use+       - prepend loading lives var to body: body can stay the same+    -}+    eid@(TxtI eidt) <- identForEntryId i+    (TxtI idt)   <- identForId i+    body <- genBody (initExprCtx i) i R2 args body+    global_occs <- globalOccs (jsSaturate (Just "ghcjs_tmp_sat_") body)+    let lidents = map global_ident global_occs+    let lids    = map global_id    global_occs+    let lidents' = map identFS lidents+    CIStaticRefs sr0 <- genStaticRefsRhs rhs+    let sri = filter (`notElem` lidents') sr0+        sr   = CIStaticRefs sri+    et <- genEntryType args+    ll <- loadLiveFun lids+    (static, regs, upd) <-+      if et == CIThunk+        then do+          r <- updateThunk+          pure (StaticThunk (Just (eidt, map StaticObjArg lidents')), CIRegs 0 [PtrV],r)+        else return (StaticFun eidt (map StaticObjArg lidents'),+                    (if null lidents then CIRegs 1 (concatMap idVt args)+                                     else CIRegs 0 (PtrV : concatMap idVt args))+                      , mempty)+    setcc <- ifProfiling $+               if et == CIThunk+                 then enterCostCentreThunk+                 else enterCostCentreFun cc+    emitClosureInfo (ClosureInfo eid+                                 regs+                                 idt+                                 (fixedLayout $ map (uTypeVt . idType) lids)+                                 et+                                 sr)+    ccId <- costCentreStackLbl cc+    emitStatic idt static ccId+    return $ (eid ||= toJExpr (JFunc [] (ll <> upd <> setcc <> body)))
+ compiler/GHC/StgToJS/CoreUtils.hs view
@@ -0,0 +1,282 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings    #-}++-- | Core utils+module GHC.StgToJS.CoreUtils where++import GHC.Prelude++import GHC.JS.Syntax++import GHC.StgToJS.Types++import GHC.Stg.Syntax++import GHC.Tc.Utils.TcType++import GHC.Builtin.Types+import GHC.Builtin.Types.Prim++import GHC.Core.DataCon+import GHC.Core.TyCo.Rep+import GHC.Core.TyCon+import GHC.Core.Type++import GHC.Types.RepType+import GHC.Types.Var+import GHC.Types.Id++import GHC.Utils.Misc+import GHC.Utils.Outputable+import GHC.Utils.Panic++import qualified Data.Bits as Bits++-- | can we unbox C x to x, only if x is represented as a Number+isUnboxableCon :: DataCon -> Bool+isUnboxableCon dc+  | [t] <- dataConRepArgTys dc+  , [t1] <- typeVt (scaledThing t)+  = isUnboxable t1 &&+    dataConTag dc == 1 &&+    length (tyConDataCons $ dataConTyCon dc) == 1+  | otherwise = False++-- | one-constructor types with one primitive field represented as a JS Number+-- can be unboxed+isUnboxable :: VarType -> Bool+isUnboxable DoubleV = True+isUnboxable IntV    = True -- includes Char#+isUnboxable _       = False++-- | Number of slots occupied by a PrimRep+data SlotCount+  = NoSlot+  | OneSlot+  | TwoSlots+  deriving (Show,Eq,Ord)++instance Outputable SlotCount where+  ppr = text . show++-- | Return SlotCount as an Int+slotCount :: SlotCount -> Int+slotCount = \case+  NoSlot   -> 0+  OneSlot  -> 1+  TwoSlots -> 2+++-- | Number of slots occupied by a value with the given VarType+varSize :: VarType -> Int+varSize = slotCount . varSlotCount++varSlotCount :: VarType -> SlotCount+varSlotCount VoidV = NoSlot+varSlotCount LongV = TwoSlots -- hi, low+varSlotCount AddrV = TwoSlots -- obj/array, offset+varSlotCount _     = OneSlot++typeSize :: Type -> Int+typeSize t = sum . map varSize . typeVt $ t++isVoid :: VarType -> Bool+isVoid VoidV = True+isVoid _     = False++isPtr :: VarType -> Bool+isPtr PtrV = True+isPtr _    = False++isSingleVar :: VarType -> Bool+isSingleVar v = varSlotCount v == OneSlot++isMultiVar :: VarType -> Bool+isMultiVar v = case varSlotCount v of+  NoSlot   -> False+  OneSlot  -> False+  TwoSlots -> True++-- | can we pattern match on these values in a case?+isMatchable :: [VarType] -> Bool+isMatchable [DoubleV] = True+isMatchable [IntV]    = True+isMatchable _         = False++tyConVt :: HasDebugCallStack => TyCon -> [VarType]+tyConVt = typeVt . mkTyConTy++idVt :: HasDebugCallStack => Id -> [VarType]+idVt = typeVt . idType++typeVt :: HasDebugCallStack => Type -> [VarType]+typeVt t | isRuntimeRepKindedTy t = []+typeVt t = map primRepVt (typePrimRep t)-- map uTypeVt (repTypeArgs t)++-- only use if you know it's not an unboxed tuple+uTypeVt :: HasDebugCallStack => UnaryType -> VarType+uTypeVt ut+  | isRuntimeRepKindedTy ut = VoidV+--  | isRuntimeRepTy ut = VoidV+  -- GHC panics on this otherwise+  | Just (tc, ty_args) <- splitTyConApp_maybe ut+  , length ty_args /= tyConArity tc = PtrV+  | isPrimitiveType ut = (primTypeVt ut)+  | otherwise          =+    case typePrimRep' ut of+      []   -> VoidV+      [pt] -> primRepVt pt+      _    -> pprPanic "uTypeVt: not unary" (ppr ut)++primRepVt :: HasDebugCallStack => PrimRep -> VarType+primRepVt VoidRep     = VoidV+primRepVt LiftedRep   = PtrV -- fixme does ByteArray# ever map to this?+primRepVt UnliftedRep = RtsObjV+primRepVt IntRep      = IntV+primRepVt Int8Rep     = IntV+primRepVt Int16Rep    = IntV+primRepVt Int32Rep    = IntV+primRepVt WordRep     = IntV+primRepVt Word8Rep    = IntV+primRepVt Word16Rep   = IntV+primRepVt Word32Rep   = IntV+primRepVt Int64Rep    = LongV+primRepVt Word64Rep   = LongV+primRepVt AddrRep     = AddrV+primRepVt FloatRep    = DoubleV+primRepVt DoubleRep   = DoubleV+primRepVt (VecRep{})  = error "uTypeVt: vector types are unsupported"++typePrimRep' :: HasDebugCallStack => UnaryType -> [PrimRep]+typePrimRep' ty = kindPrimRep' empty (typeKind ty)++-- | Find the primitive representation of a 'TyCon'. Defined here to+-- avoid module loops. Call this only on unlifted tycons.+tyConPrimRep' :: HasDebugCallStack => TyCon -> [PrimRep]+tyConPrimRep' tc = kindPrimRep' empty res_kind+  where+    res_kind = tyConResKind tc++-- | Take a kind (of shape @TYPE rr@) and produce the 'PrimRep's+-- of values of types of this kind.+kindPrimRep' :: HasDebugCallStack => SDoc -> Kind -> [PrimRep]+kindPrimRep' doc ki+  | Just ki' <- coreView ki+  = kindPrimRep' doc ki'+kindPrimRep' doc (TyConApp _typ [runtime_rep])+  = -- ASSERT( typ `hasKey` tYPETyConKey )+    runtimeRepPrimRep doc runtime_rep+kindPrimRep' doc ki+  = pprPanic "kindPrimRep'" (ppr ki $$ doc)++primTypeVt :: HasDebugCallStack => Type -> VarType+primTypeVt t = case tyConAppTyCon_maybe (unwrapType t) of+  Nothing -> error "primTypeVt: not a TyCon"+  Just tc+    | tc == charPrimTyCon              -> IntV+    | tc == intPrimTyCon               -> IntV+    | tc == wordPrimTyCon              -> IntV+    | tc == floatPrimTyCon             -> DoubleV+    | tc == doublePrimTyCon            -> DoubleV+    | tc == int8PrimTyCon              -> IntV+    | tc == word8PrimTyCon             -> IntV+    | tc == int16PrimTyCon             -> IntV+    | tc == word16PrimTyCon            -> IntV+    | tc == int32PrimTyCon             -> IntV+    | tc == word32PrimTyCon            -> IntV+    | tc == int64PrimTyCon             -> LongV+    | tc == word64PrimTyCon            -> LongV+    | tc == addrPrimTyCon              -> AddrV+    | tc == stablePtrPrimTyCon         -> AddrV+    | tc == stableNamePrimTyCon        -> RtsObjV+    | tc == statePrimTyCon             -> VoidV+    | tc == proxyPrimTyCon             -> VoidV+    | tc == realWorldTyCon             -> VoidV+    | tc == threadIdPrimTyCon          -> RtsObjV+    | tc == weakPrimTyCon              -> RtsObjV+    | tc == arrayPrimTyCon             -> ArrV+    | tc == smallArrayPrimTyCon        -> ArrV+    | tc == byteArrayPrimTyCon         -> ObjV -- can contain any JS reference, used for JSVal+    | tc == mutableArrayPrimTyCon      -> ArrV+    | tc == smallMutableArrayPrimTyCon -> ArrV+    | tc == mutableByteArrayPrimTyCon  -> ObjV -- can contain any JS reference, used for JSVal+    | tc == mutVarPrimTyCon            -> RtsObjV+    | tc == mVarPrimTyCon              -> RtsObjV+    | tc == tVarPrimTyCon              -> RtsObjV+    | tc == bcoPrimTyCon               -> RtsObjV -- unsupported?+    | tc == stackSnapshotPrimTyCon     -> RtsObjV+    | tc == ioPortPrimTyCon            -> RtsObjV -- unsupported?+    | tc == anyTyCon                   -> PtrV+    | tc == compactPrimTyCon           -> ObjV -- unsupported?+    | tc == eqPrimTyCon                -> VoidV -- coercion token?+    | tc == eqReprPrimTyCon            -> VoidV -- role+    | tc == unboxedUnitTyCon           -> VoidV -- Void#+    | otherwise                        -> PtrV  -- anything else must be some boxed thing++argVt :: StgArg -> VarType+argVt a = uTypeVt . stgArgType $ a++dataConType :: DataCon -> Type+dataConType dc = idType (dataConWrapId dc)++isBoolDataCon :: DataCon -> Bool+isBoolDataCon dc = isBoolTy (dataConType dc)++-- standard fixed layout: payload types+-- payload starts at .d1 for heap objects, entry closest to Sp for stack frames+fixedLayout :: [VarType] -> CILayout+fixedLayout vts = CILayoutFixed (sum (map varSize vts)) vts++-- 2-var values might have been moved around separately, use DoubleV as substitute+-- ObjV is 1 var, so this is no problem for implicit metadata+stackSlotType :: Id -> VarType+stackSlotType i+  | OneSlot <- varSlotCount otype = otype+  | otherwise                     = DoubleV+  where otype = uTypeVt (idType i)++idPrimReps :: Id -> [PrimRep]+idPrimReps = typePrimReps . idType++typePrimReps :: Type -> [PrimRep]+typePrimReps = typePrimRep . unwrapType++primRepSize :: PrimRep -> SlotCount+primRepSize p = varSlotCount (primRepVt p)++-- | Associate the given values to each RrimRep in the given order, taking into+-- account the number of slots per PrimRep+assocPrimReps :: Outputable a => [PrimRep] -> [a] -> [(PrimRep, [a])]+assocPrimReps []     _  = []+assocPrimReps (r:rs) vs = case (primRepSize r,vs) of+  (NoSlot,   xs)     -> (r,[])    : assocPrimReps rs xs+  (OneSlot,  x:xs)   -> (r,[x])   : assocPrimReps rs xs+  (TwoSlots, x:y:xs) -> (r,[x,y]) : assocPrimReps rs xs+  err                -> pprPanic "assocPrimReps" (ppr err)++-- | Associate the given values to the Id's PrimReps, taking into account the+-- number of slots per PrimRep+assocIdPrimReps :: Outputable a => Id -> [a] -> [(PrimRep, [a])]+assocIdPrimReps i = assocPrimReps (idPrimReps i)++-- | Associate the given JExpr to the Id's PrimReps, taking into account the+-- number of slots per PrimRep+assocIdExprs :: Id -> [JExpr] -> [TypedExpr]+assocIdExprs i es = fmap (uncurry TypedExpr) (assocIdPrimReps i es)++-- | Return False only if we are *sure* it's a data type+-- Look through newtypes etc as much as possible+might_be_a_function :: HasDebugCallStack => Type -> Bool+might_be_a_function ty+  | [LiftedRep] <- typePrimRep ty+  , Just tc <- tyConAppTyCon_maybe (unwrapType ty)+  , isDataTyCon tc+  = False+  | otherwise+  = True++mkArityTag :: Int -> Int -> Int+mkArityTag arity registers = arity Bits..|. (registers `Bits.shiftL` 8)++toTypeList :: [VarType] -> [Int]+toTypeList = concatMap (\x -> replicate (varSize x) (fromEnum x))
+ compiler/GHC/StgToJS/DataCon.hs view
@@ -0,0 +1,124 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.DataCon+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+--  Code generation of data constructors+-----------------------------------------------------------------------------++module GHC.StgToJS.DataCon+  ( genCon+  , allocCon+  , allocUnboxedCon+  , allocDynamicE+  , allocDynamic+  )+where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Make++import GHC.StgToJS.Closure+import GHC.StgToJS.ExprCtx+import GHC.StgToJS.Types+import GHC.StgToJS.Monad+import GHC.StgToJS.CoreUtils+import GHC.StgToJS.Profiling+import GHC.StgToJS.Utils+import GHC.StgToJS.Ids++import GHC.Core.DataCon++import GHC.Types.CostCentre+import GHC.Types.Unique.Map++import GHC.Utils.Outputable+import GHC.Utils.Panic+import GHC.Data.FastString++import Data.Maybe++-- | Generate a data constructor. Special handling for unboxed tuples+genCon :: ExprCtx -> DataCon -> [JExpr] -> G JStat+genCon ctx con args+  | isUnboxedTupleDataCon con+  = return $ assignToExprCtx ctx args++  | [ValExpr (JVar ctxi)] <- concatMap typex_expr (ctxTarget ctx)+  = allocCon ctxi con currentCCS args++  | xs <- concatMap typex_expr (ctxTarget ctx)+  = pprPanic "genCon: unhandled DataCon" (ppr (con, args, xs))++-- | Allocate a data constructor. Allocate in this context means bind the data+-- constructor to 'to'+allocCon :: Ident -> DataCon -> CostCentreStack -> [JExpr] -> G JStat+allocCon to con cc xs+  | isBoolDataCon con || isUnboxableCon con =+      return (toJExpr to |= allocUnboxedCon con xs)+{-  | null xs = do+      i <- varForId (dataConWorkId con)+      return (assignj to i) -}+  | otherwise = do+      e <- varForDataConWorker con+      cs <- getSettings+      prof <- profiling+      ccsJ <- if prof then ccsVarJ cc else return Nothing+      return $ allocDynamic cs False to e xs ccsJ++-- | Allocate an unboxed data constructor. If we have a bool we calculate the+-- right value. If not then we expect a singleton list and unbox by converting+-- ''C x' to 'x'. NB. This function may panic.+allocUnboxedCon :: DataCon -> [JExpr] -> JExpr+allocUnboxedCon con = \case+  []+    | isBoolDataCon con && dataConTag con == 1 -> false_+    | isBoolDataCon con && dataConTag con == 2 -> true_+  [x]+    | isUnboxableCon con -> x+  xs -> pprPanic "allocUnboxedCon: not an unboxed constructor" (ppr (con,xs))++-- | Allocate an entry function. See 'GHC.StgToJS.hs' for the object layout.+allocDynamicE :: Bool          -- ^ csInlineAlloc from StgToJSConfig+              -> JExpr+              -> [JExpr]+              -> Maybe JExpr+              -> JExpr+allocDynamicE  inline_alloc entry free cc+  | inline_alloc || length free > 24 = newClosure $ Closure+      { clEntry  = entry+      , clField1 = fillObj1+      , clField2 = fillObj2+      , clMeta   = ValExpr (JInt 0)+      , clCC     = cc+      }+  | otherwise = ApplExpr allocFun (toJExpr entry : free ++ maybeToList cc)+  where+    allocFun = allocClsA (length free)+    (fillObj1,fillObj2)+       = case free of+                []  -> (null_, null_)+                [x] -> (x,null_)+                [x,y] -> (x,y)+                (x:xs) -> (x,toJExpr (JHash $ listToUniqMap (zip dataFields xs)))+    dataFields = map (mkFastString . ('d':) . show) [(1::Int)..]++-- | Allocate a dynamic object+allocDynamic :: StgToJSConfig -> Bool -> Ident -> JExpr -> [JExpr] -> Maybe JExpr -> JStat+allocDynamic s need_decl to entry free cc+  | need_decl = DeclStat to (Just value)+  | otherwise = toJExpr to |= value+    where+      value = allocDynamicE (csInlineAlloc s) entry free cc
+ compiler/GHC/StgToJS/Deps.hs view
@@ -0,0 +1,191 @@+{-# LANGUAGE TupleSections #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Deps+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+-- Module to calculate the transitive dependencies of a module+-----------------------------------------------------------------------------++module GHC.StgToJS.Deps+  ( genDependencyData+  )+where++import GHC.Prelude++import GHC.StgToJS.Object as Object+import GHC.StgToJS.Types+import GHC.StgToJS.Ids++import GHC.JS.Syntax++import GHC.Types.Id+import GHC.Types.Unique+import GHC.Types.Unique.FM+import GHC.Types.Name++import GHC.Unit.Module++import GHC.Utils.Misc+import GHC.Utils.Outputable+import GHC.Utils.Panic++import GHC.Data.FastString++import Data.Map (Map)+import qualified Data.Map as M+import qualified Data.Set as S+import qualified Data.IntSet as IS+import qualified Data.IntMap as IM+import Data.IntMap (IntMap)+import Data.Array+import Data.Either+import Control.Monad++import Control.Monad.Trans.Class+import Control.Monad.Trans.State++data DependencyDataCache = DDC+  { ddcModule :: !(IntMap Unit)               -- ^ Unique Module -> Unit+  , ddcId     :: !(IntMap Object.ExportedFun) -- ^ Unique Id     -> Object.ExportedFun (only to other modules)+  , ddcOther  :: !(Map OtherSymb Object.ExportedFun)+  }++-- | Generate module dependency data+--+-- Generate the object's dependency data, taking care that package and module names+-- are only stored once+genDependencyData+  :: HasDebugCallStack+  => Module+  -> [LinkableUnit]+  -> G Object.Deps+genDependencyData mod units = do+    -- [(blockindex, blockdeps, required, exported)]+    ds <- evalStateT (mapM (uncurry oneDep) blocks)+                     (DDC IM.empty IM.empty M.empty)+    return $ Object.Deps+      { depsModule          = mod+      , depsRequired        = IS.fromList [ n | (n, _, True, _) <- ds ]+      , depsHaskellExported = M.fromList $ (\(n,_,_,es) -> map (,n) es) =<< ds+      , depsBlocks          = listArray (0, length blocks-1) (map (\(_,deps,_,_) -> deps) ds)+      }+  where+      -- Id -> Block+      unitIdExports :: UniqFM Id Int+      unitIdExports = listToUFM $+                      concatMap (\(u,n) -> map (,n) (luIdExports u)) blocks++      -- OtherSymb -> Block+      unitOtherExports :: Map OtherSymb Int+      unitOtherExports = M.fromList $+                         concatMap (\(u,n) -> map (,n)+                                                  (map (OtherSymb mod)+                                                       (luOtherExports u)))+                                   blocks++      blocks :: [(LinkableUnit, Int)]+      blocks = zip units [0..]++      -- generate the list of exports and set of dependencies for one unit+      oneDep :: LinkableUnit+             -> Int+             -> StateT DependencyDataCache G (Int, Object.BlockDeps, Bool, [Object.ExportedFun])+      oneDep (LinkableUnit _ idExports otherExports idDeps pseudoIdDeps otherDeps req _frefs) n = do+        (edi, bdi) <- partitionEithers <$> mapM (lookupIdFun n) idDeps+        (edo, bdo) <- partitionEithers <$> mapM lookupOtherFun otherDeps+        (edp, bdp) <- partitionEithers <$> mapM (lookupPseudoIdFun n) pseudoIdDeps+        expi <- mapM lookupExportedId (filter isExportedId idExports)+        expo <- mapM lookupExportedOther otherExports+        -- fixme thin deps, remove all transitive dependencies!+        let bdeps = Object.BlockDeps+                      (IS.toList . IS.fromList . filter (/=n) $ bdi++bdo++bdp)+                      (S.toList . S.fromList $ edi++edo++edp)+        return (n, bdeps, req, expi++expo)++      idModule :: Id -> Maybe Module+      idModule i = nameModule_maybe (getName i) >>= \m ->+                   guard (m /= mod) >> return m++      lookupPseudoIdFun :: Int -> Unique+                        -> StateT DependencyDataCache G (Either Object.ExportedFun Int)+      lookupPseudoIdFun _n u =+        case lookupUFM_Directly unitIdExports u of+          Just k -> return (Right k)+          _      -> panic "lookupPseudoIdFun"++      -- get the function for an Id from the cache, add it if necessary+      -- result: Left Object.ExportedFun   if function refers to another module+      --         Right blockNumber if function refers to current module+      --+      --         assumes function is internal to the current block if it's+      --         from teh current module and not in the unitIdExports map.+      lookupIdFun :: Int -> Id+                  -> StateT DependencyDataCache G (Either Object.ExportedFun Int)+      lookupIdFun n i = case lookupUFM unitIdExports i of+        Just k  -> return (Right k)+        Nothing -> case idModule i of+          Nothing -> return (Right n)+          Just m ->+            let k = getKey . getUnique $ i+                addEntry :: StateT DependencyDataCache G Object.ExportedFun+                addEntry = do+                  (TxtI idTxt) <- lift (identForId i)+                  lookupExternalFun (Just k) (OtherSymb m idTxt)+            in  if m == mod+                   then pprPanic "local id not found" (ppr m)+                    else Left <$> do+                            mr <- gets (IM.lookup k . ddcId)+                            maybe addEntry return mr++      -- get the function for an OtherSymb from the cache, add it if necessary+      lookupOtherFun :: OtherSymb+                     -> StateT DependencyDataCache G (Either Object.ExportedFun Int)+      lookupOtherFun od@(OtherSymb m idTxt) =+        case M.lookup od unitOtherExports of+          Just n  -> return (Right n)+          Nothing | m == mod -> panic ("genDependencyData.lookupOtherFun: unknown local other id: " ++ unpackFS idTxt)+          Nothing ->  Left <$> (maybe (lookupExternalFun Nothing od) return =<<+                        gets (M.lookup od . ddcOther))++      lookupExportedId :: Id -> StateT DependencyDataCache G Object.ExportedFun+      lookupExportedId i = do+        (TxtI idTxt) <- lift (identForId i)+        lookupExternalFun (Just . getKey . getUnique $ i) (OtherSymb mod idTxt)++      lookupExportedOther :: FastString -> StateT DependencyDataCache G Object.ExportedFun+      lookupExportedOther = lookupExternalFun Nothing . OtherSymb mod++      -- lookup a dependency to another module, add to the id cache if there's+      -- an id key, otherwise add to other cache+      lookupExternalFun :: Maybe Int+                        -> OtherSymb -> StateT DependencyDataCache G Object.ExportedFun+      lookupExternalFun mbIdKey od@(OtherSymb m idTxt) = do+        let mk        = getKey . getUnique $ m+            mpk       = moduleUnit m+            exp_fun   = Object.ExportedFun m (LexicalFastString idTxt)+            addCache  = do+              ms <- gets ddcModule+              let !cache' = IM.insert mk mpk ms+              modify (\s -> s { ddcModule = cache'})+              pure exp_fun+        f <- do+          mbm <- gets (IM.member mk . ddcModule)+          case mbm of+            False -> addCache+            True  -> pure exp_fun++        case mbIdKey of+          Nothing -> modify (\s -> s { ddcOther = M.insert od f (ddcOther s) })+          Just k  -> modify (\s -> s { ddcId    = IM.insert k f (ddcId s) })++        return f
+ compiler/GHC/StgToJS/Expr.hs view
@@ -0,0 +1,1045 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveFunctor #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Expr+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+--  Code generation of Expressions+-----------------------------------------------------------------------------++module GHC.StgToJS.Expr+  ( genExpr+  , genEntryType+  , loadLiveFun+  , genStaticRefsRhs+  , genStaticRefs+  , genBody+  )+where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Make++import GHC.StgToJS.Apply+import GHC.StgToJS.Arg+import GHC.StgToJS.ExprCtx+import GHC.StgToJS.FFI+import GHC.StgToJS.Heap+import GHC.StgToJS.Monad+import GHC.StgToJS.DataCon+import GHC.StgToJS.Types+import GHC.StgToJS.Literal+import GHC.StgToJS.Prim+import GHC.StgToJS.Profiling+import GHC.StgToJS.Regs+import GHC.StgToJS.StgUtils+import GHC.StgToJS.CoreUtils+import GHC.StgToJS.Utils+import GHC.StgToJS.Stack+import GHC.StgToJS.Ids++import GHC.Types.Basic+import GHC.Types.CostCentre+import GHC.Types.Tickish+import GHC.Types.Var.Set+import GHC.Types.Id+import GHC.Types.Unique.FM+import GHC.Types.RepType++import GHC.Stg.Syntax+import GHC.Stg.Utils++import GHC.Builtin.PrimOps++import GHC.Core+import GHC.Core.TyCon+import GHC.Core.DataCon+import GHC.Core.Opt.Arity (isOneShotBndr)+import GHC.Core.Type hiding (typeSize)++import GHC.Utils.Misc+import GHC.Utils.Monad+import GHC.Utils.Panic+import GHC.Utils.Panic.Plain+import GHC.Utils.Outputable (ppr, renderWithContext, defaultSDocContext)+import qualified Control.Monad.Trans.State.Strict as State+import GHC.Data.FastString+import qualified GHC.Data.List.SetOps as ListSetOps++import Data.Monoid+import Data.Maybe+import Data.Function+import Data.Either+import qualified Data.List as L+import qualified Data.Set as S+import qualified Data.Map as M+import Control.Monad+import Control.Arrow ((&&&))++-- | Evaluate an expression in the given expression context (continuation)+genExpr :: HasDebugCallStack => ExprCtx -> CgStgExpr -> G (JStat, ExprResult)+genExpr ctx stg = case stg of+  StgApp f args -> genApp ctx f args+  StgLit l      -> do+    ls <- genLit l+    let r = assignToExprCtx ctx ls+    pure (r,ExprInline Nothing)+  StgConApp con _n args _ -> do+    as <- concatMapM genArg args+    c <- genCon ctx con as+    return (c, ExprInline (Just as))+  StgOpApp (StgFCallOp f _) args t+    -> genForeignCall ctx f t (concatMap typex_expr $ ctxTarget ctx) args+  StgOpApp (StgPrimOp op) args t+    -> genPrimOp ctx op args t+  StgOpApp (StgPrimCallOp c) args t+    -> genPrimCall ctx c args t+  StgCase e b at alts+    -> genCase ctx b e at alts (liveVars $ stgExprLive False stg)+  StgLet _ b e -> do+    (b',ctx') <- genBind ctx b+    (s,r)     <- genExpr ctx' e+    return (b' <> s, r)+  StgLetNoEscape _ b e -> do+    (b', ctx') <- genBindLne ctx b+    (s, r)     <- genExpr ctx' e+    return (b' <> s, r)+  StgTick (ProfNote cc count scope) e -> do+    setSCCstats <- ifProfilingM $ setCC cc count scope+    (stats, result) <- genExpr ctx e+    return (setSCCstats <> stats, result)+  StgTick (SourceNote span _sname) e+    -> genExpr (ctxSetSrcSpan span ctx) e+  StgTick _m e+    -> genExpr ctx e++-- | regular let binding: allocate heap object+genBind :: HasDebugCallStack+        => ExprCtx+        -> CgStgBinding+        -> G (JStat, ExprCtx)+genBind ctx bndr =+  case bndr of+    StgNonRec b r -> do+       j <- assign b r >>= \case+         Just ja -> return ja+         Nothing -> allocCls Nothing [(b,r)]+       return (j, addEvalRhs ctx [(b,r)])+    StgRec bs     -> do+       jas <- mapM (uncurry assign) bs -- fixme these might depend on parts initialized by allocCls+       let m = if null jas then Nothing else Just (mconcat $ catMaybes jas)+       j <- allocCls m . map snd . filter (isNothing . fst) $ zip jas bs+       return (j, addEvalRhs ctx bs)+   where+     ctx' = ctxClearLneFrame ctx++     assign :: Id -> CgStgRhs -> G (Maybe JStat)+     assign b (StgRhsClosure _ _ccs {-[the_fv]-} _upd [] expr)+       | let strip = snd . stripStgTicksTop (not . tickishIsCode)+       , StgCase (StgApp scrutinee []) _ (AlgAlt _) [GenStgAlt (DataAlt _) params sel_expr] <- strip expr+       , StgApp selectee [] <- strip sel_expr+       , let params_w_offsets = zip params (L.scanl' (+) 1 $ map (typeSize . idType) params)+       , let total_size = sum (map (typeSize . idType) params)+       -- , the_fv == scrutinee -- fixme check+       , Just the_offset <- ListSetOps.assocMaybe params_w_offsets selectee+       , the_offset <= 16 -- fixme make this some configurable constant+       = do+           let the_fv = scrutinee -- error "the_fv" -- fixme+           let sel_tag | the_offset == 2 = if total_size == 2 then "2a"+                                                              else "2b"+                       | otherwise       = show the_offset+           tgts <- identsForId b+           the_fvjs <- varsForId the_fv+           case (tgts, the_fvjs) of+             ([tgt], [the_fvj]) -> return $ Just+               (tgt ||= ApplExpr (var ("h$c_sel_" <> mkFastString sel_tag)) [the_fvj])+             _ -> panic "genBind.assign: invalid size"+     assign b (StgRhsClosure _ext _ccs _upd [] expr)+       | snd (isInlineExpr (ctxEvaluatedIds ctx) expr) = do+           d   <- declVarsForId b+           tgt <- varsForId b+           let ctx' = ctx { ctxTarget = assocIdExprs b tgt }+           (j, _) <- genExpr ctx' expr+           return (Just (d <> j))+     assign _b StgRhsCon{} = return Nothing+     assign  b r           = genEntry ctx' b r >> return Nothing++     addEvalRhs c [] = c+     addEvalRhs c ((b,r):xs)+       | StgRhsCon{} <- r                       = addEvalRhs (ctxAssertEvaluated b c) xs+       | (StgRhsClosure _ _ ReEntrant _ _) <- r = addEvalRhs (ctxAssertEvaluated b c) xs+       | otherwise                              = addEvalRhs c xs++genBindLne :: HasDebugCallStack+           => ExprCtx+           -> CgStgBinding+           -> G (JStat, ExprCtx)+genBindLne ctx bndr = do+  -- compute live variables and the offsets where they will be stored in the+  -- stack+  vis  <- map (\(x,y,_) -> (x,y)) <$>+            optimizeFree oldFrameSize (newLvs++map fst updBinds)+  -- initialize updatable bindings to null_+  declUpds <- mconcat <$> mapM (fmap (||= null_) . identForId . fst) updBinds+  -- update expression context to include the updated LNE frame+  let ctx' = ctxUpdateLneFrame vis bound ctx+  mapM_ (uncurry $ genEntryLne ctx') binds+  return (declUpds, ctx')+  where+    oldFrameSize = ctxLneFrameSize ctx+    isOldLv i    = ctxIsLneBinding ctx i ||+                   ctxIsLneLiveVar ctx i+    live         = liveVars $ mkDVarSet $ stgLneLive' bndr+    newLvs       = filter (not . isOldLv) (dVarSetElems live)+    binds = case bndr of+              StgNonRec b e -> [(b,e)]+              StgRec    bs  -> bs+    bound = map fst binds+    (updBinds, _nonUpdBinds) = L.partition (isUpdatableRhs . snd) binds++-- | Generate let-no-escape entry+--+-- Let-no-escape entries live on the stack. There is no heap object associated with them.+--+-- A let-no-escape entry is called like a normal stack frame, although as an optimization,+-- `Stack`[`Sp`] is not set when making the call. This is done later if the+-- thread needs to be suspended.+--+-- Updatable let-no-escape binders have one 'private' slot in the stack frame. This slot+-- is initially set to null, changed to h$blackhole when the thunk is being evaluated.+--+genEntryLne :: HasDebugCallStack => ExprCtx -> Id -> CgStgRhs -> G ()+genEntryLne ctx i rhs@(StgRhsClosure _ext _cc update args body) =+  resetSlots $ do+  let payloadSize = ctxLneFrameSize ctx+      vars        = ctxLneFrameVars ctx+      myOffset    =+        maybe (panic "genEntryLne: updatable binder not found in let-no-escape frame")+              ((payloadSize-) . fst)+              (L.find ((==i) . fst . snd) (zip [0..] vars))+      bh | isUpdatable update =+             jVar (\x -> mconcat+              [ x |= ApplExpr (var "h$bh_lne") [Sub sp (toJExpr myOffset), toJExpr (payloadSize+1)]+              , IfStat x (ReturnStat x) mempty+              ])+         | otherwise = mempty+  lvs  <- popLneFrame True payloadSize ctx+  body <- genBody ctx i R1 args body+  ei@(TxtI eii) <- identForEntryId i+  sr   <- genStaticRefsRhs rhs+  let f = JFunc [] (bh <> lvs <> body)+  emitClosureInfo $+    ClosureInfo ei+                (CIRegs 0 $ concatMap idVt args)+                (eii <> ", " <> mkFastString (renderWithContext defaultSDocContext (ppr i)))+                (fixedLayout . reverse $+                    map (stackSlotType . fst) (ctxLneFrameVars ctx))+                CIStackFrame+                sr+  emitToplevel (ei ||= toJExpr f)+genEntryLne ctx i (StgRhsCon cc con _mu _ticks args) = resetSlots $ do+  let payloadSize = ctxLneFrameSize ctx+  ei@(TxtI _eii) <- identForEntryId i+  -- di <- varForDataConWorker con+  ii <- freshIdent+  p  <- popLneFrame True payloadSize ctx+  args' <- concatMapM genArg args+  ac    <- allocCon ii con cc args'+  emitToplevel (ei ||= toJExpr (JFunc []+    (mconcat [decl ii, p, ac, r1 |= toJExpr ii, returnStack])))++-- | Generate the entry function for a local closure+genEntry :: HasDebugCallStack => ExprCtx -> Id -> CgStgRhs -> G ()+genEntry _ _i StgRhsCon {} = return ()+genEntry ctx i rhs@(StgRhsClosure _ext cc {-_bi live-} upd_flag args body) = resetSlots $ do+  let live = stgLneLiveExpr rhs -- error "fixme" -- probably find live vars in body+  ll    <- loadLiveFun live+  llv   <- verifyRuntimeReps live+  upd   <- genUpdFrame upd_flag i+  body  <- genBody entryCtx i R2 args body+  ei@(TxtI eii) <- identForEntryId i+  et    <- genEntryType args+  setcc <- ifProfiling $+             if et == CIThunk+               then enterCostCentreThunk+               else enterCostCentreFun cc+  sr <- genStaticRefsRhs rhs+  emitClosureInfo $ ClosureInfo ei+                                (CIRegs 0 $ PtrV : concatMap idVt args)+                                (eii <> ", " <> mkFastString (renderWithContext defaultSDocContext (ppr i)))+                                (fixedLayout $ map (uTypeVt . idType) live)+                                et+                                sr+  emitToplevel (ei ||= toJExpr (JFunc [] (mconcat [ll, llv, upd, setcc, body])))+  where+    entryCtx = ctxSetTarget [] (ctxClearLneFrame ctx)++-- | Generate the entry function types for identifiers. Note that this only+-- returns either 'CIThunk' or 'CIFun'. Everything else (PAP Blackhole etc.) is+-- filtered as not a RuntimeRepKinded type.+genEntryType :: HasDebugCallStack => [Id] -> G CIType+genEntryType []   = return CIThunk+genEntryType args0 = do+  args' <- mapM genIdArg args+  return $ CIFun (length args) (length $ concat args')+  where+    args = filter (not . isRuntimeRepKindedTy . idType) args0++-- | Generate the body of an object+genBody :: HasDebugCallStack+         => ExprCtx+         -> Id+         -> StgReg+         -> [Id]+         -> CgStgExpr+         -> G JStat+genBody ctx i startReg args e = do+  -- load arguments into local variables+  la <- do+    args' <- concatMapM genIdArgI args+    return (declAssignAll args' (fmap toJExpr [startReg..]))++  -- assert that arguments have valid runtime reps+  lav <- verifyRuntimeReps args++  -- compute PrimReps and their number of slots required to return the result of+  -- i applied to args.+  let res_vars = resultSize args i++  -- compute typed expressions for each slot and assign registers+  let go_var regs = \case+        []              -> []+        ((rep,size):rs) ->+          let !(regs0,regs1) = splitAt size regs+              !ts = go_var regs1 rs+          in TypedExpr rep regs0 : ts++  let tgt  = go_var jsRegsFromR1 res_vars+  let !ctx' = ctx { ctxTarget = tgt }++  -- generate code for the expression+  (e, _r) <- genExpr ctx' e++  return $ la <> lav <> e <> returnStack++-- | Find the result type after applying the function to the arguments+--+-- It's trickier than it looks because:+--+-- 1. we don't have the Arity of the Id. The following functions return+-- different values in some cases:+--    - idArity+--    - typeArity . idType+--    - idFunRepArity+--    - typeArity . unwrapType . idType+-- Moreover the number of args may be different than all of these arities+--+-- 2. sometimes the type is Any, perhaps after some unwrapping. For example+-- HappyAbsSyn is a newtype around HappyAny which is Any or (forall a. a).+--+-- Se we're left to use the applied arguments to peel the type (unwrapped) one+-- arg at a time. But passed args are args after unarisation so we need to+-- unarise every argument type that we peel (using typePrimRepArgs) to get the+-- number of passed args consumed by each type arg.+--+-- In case of failure to determine the type, we default to LiftedRep as it's+-- probably what it is.+--+resultSize :: HasDebugCallStack => [Id] -> Id -> [(PrimRep, Int)]+resultSize args i = result+  where+    result       = result_reps `zip` result_slots+    result_slots = fmap (slotCount . primRepSize) result_reps+    result_reps  = trim_args (unwrapType (idType i)) (length args)++    trim_args t 0 = typePrimRep t+    trim_args t n+      | Just (_af, _mult, arg, res) <- splitFunTy_maybe t+      , nargs <- length (typePrimRepArgs arg)+      , assert (n >= nargs) True+      = trim_args (unwrapType res) (n - nargs)+      | otherwise+      = pprTrace "result_type: not a function type, assume LiftedRep" (ppr t)+          [LiftedRep]++-- | Ensure that the set of identifiers has valid 'RuntimeRep's. This function+-- returns a no-op when 'csRuntimeAssert' in 'StgToJSConfig' is False.+verifyRuntimeReps :: HasDebugCallStack => [Id] -> G JStat+verifyRuntimeReps xs = do+  runtime_assert <- csRuntimeAssert <$> getSettings+  if not runtime_assert+    then pure mempty+    else mconcat <$> mapM verifyRuntimeRep xs+  where+    verifyRuntimeRep i = do+      i' <- varsForId i+      pure $ go i' (idVt i)+    go js         (VoidV:vs) = go js vs+    go (j1:j2:js) (LongV:vs) = v "h$verify_rep_long" [j1,j2] <> go js vs+    go (j1:j2:js) (AddrV:vs) = v "h$verify_rep_addr" [j1,j2] <> go js vs+    go (j:js)     (v:vs)     = ver j v                       <> go js vs+    go []         []         = mempty+    go _          _          = pprPanic "verifyRuntimeReps: inconsistent sizes" (ppr xs)+    ver j PtrV    = v "h$verify_rep_heapobj" [j]+    ver j IntV    = v "h$verify_rep_int"     [j]+    ver j RtsObjV = v "h$verify_rep_rtsobj"  [j]+    ver j DoubleV = v "h$verify_rep_double"  [j]+    ver j ArrV    = v "h$verify_rep_arr"     [j]+    ver _ _       = mempty+    v f as = ApplStat (var f) as++-- | Given a set of 'Id's, bind each 'Id' to the appropriate data fields in N+-- registers. This assumes these data fields have already been populated in the+-- registers. For the empty, singleton, and binary case use register 1, for any+-- more use as many registers as necessary.+loadLiveFun :: [Id] -> G JStat+loadLiveFun l = do+   l' <- concat <$> mapM identsForId l+   case l' of+     []  -> return mempty+     -- set the ident to d1 field of register 1+     [v] -> return (v ||= r1 .^ closureField1_)+     -- set the idents to d1 and d2 fields of register 1+     [v1,v2] -> return $ mconcat+                        [ v1 ||= r1 .^ closureField1_+                        , v2 ||= r1 .^ closureField2_+                        ]+     -- and so on+     (v:vs)  -> do+       d <- freshIdent+       let l'' = mconcat . zipWith (loadLiveVar $ toJExpr d) [(1::Int)..] $ vs+       return $ mconcat+               [ v ||= r1 .^ closureField1_+               , d ||= r1 .^ closureField2_+               , l''+               ]+  where+        loadLiveVar d n v = let ident = TxtI (dataFieldName n)+                            in  v ||= SelExpr d ident++-- | Pop a let-no-escape frame off the stack+popLneFrame :: Bool -> Int -> ExprCtx -> G JStat+popLneFrame inEntry size ctx = do+  -- calculate the new stack size+  let ctx' = ctxLneShrinkStack ctx size++  let gen_id_slot (i,n) = do+        ids <- identsForId i+        let !id_n = ids !! (n-1)+        pure (id_n, SlotId i n)++  is <- mapM gen_id_slot (ctxLneFrameVars ctx')++  let skip = if inEntry then 1 else 0 -- pop the frame header+  popSkipI skip is++-- | Generate an updated given an 'Id'+genUpdFrame :: UpdateFlag -> Id -> G JStat+genUpdFrame u i+  | isReEntrant u   = pure mempty+  | isOneShotBndr i = maybeBh+  | isUpdatable u   = updateThunk+  | otherwise       = maybeBh+  where+    isReEntrant ReEntrant = True+    isReEntrant _         = False+    maybeBh = do+      settings <- getSettings+      assertRtsStat (return $ bhSingleEntry settings)++-- | Blackhole single entry+--+-- Overwrite a single entry object with a special thunk that behaves like a+-- black hole (throws a JS exception when entered) but pretends to be a thunk.+-- Useful for making sure that the object is not accidentally entered multiple+-- times+--+bhSingleEntry :: StgToJSConfig -> JStat+bhSingleEntry _settings = mconcat+  [ r1 .^ closureEntry_  |= var "h$blackholeTrap"+  , r1 .^ closureField1_ |= undefined_+  , r1 .^ closureField2_ |= undefined_+  ]++genStaticRefsRhs :: CgStgRhs -> G CIStatic+genStaticRefsRhs lv = genStaticRefs (stgRhsLive lv)++-- fixme, update to new way to compute static refs dynamically+genStaticRefs :: LiveVars -> G CIStatic+genStaticRefs lv+  | isEmptyDVarSet sv = return (CIStaticRefs [])+  | otherwise         = do+      unfloated <- State.gets gsUnfloated+      let xs = filter (\x -> not (elemUFM x unfloated ||+                                  typeLevity_maybe (idType x) == Just Unlifted))+                      (dVarSetElems sv)+      CIStaticRefs . catMaybes <$> mapM getStaticRef xs+  where+    sv = liveStatic lv++    getStaticRef :: Id -> G (Maybe FastString)+    getStaticRef = fmap (fmap itxt . listToMaybe) . identsForId++-- | Reorder the things we need to push to reuse existing stack values as much+-- as possible True if already on the stack at that location+optimizeFree+  :: HasDebugCallStack+  => Int+  -> [Id]+  -> G [(Id,Int,Bool)] -- ^ A list of stack slots.+                       -- -- Id: stored on the slot+                       -- -- Int: the part of the value that is stored+                       -- -- Bool: True when the slot already contains a value+optimizeFree offset ids = do+  -- this line goes wrong                               vvvvvvv+  let -- ids' = concat $ map (\i -> map (i,) [1..varSize . uTypeVt . idType $ i]) ids+      idSize :: Id -> Int+      idSize i = sum $ map varSize (typeVt . idType $ i)+      ids' = concatMap (\i -> map (i,) [1..idSize i]) ids+      -- 1..varSize] . uTypeVt . idType $ i]) (typeVt ids)+      l    = length ids'+  slots <- drop offset . take l . (++repeat SlotUnknown) <$> getSlots+  let slm                = M.fromList (zip slots [0..])+      (remaining, fixed) = partitionEithers $+         map (\inp@(i,n) -> maybe (Left inp) (\j -> Right (i,n,j,True))+            (M.lookup (SlotId i n) slm)) ids'+      takenSlots         = S.fromList (fmap (\(_,_,x,_) -> x) fixed)+      freeSlots          = filter (`S.notMember` takenSlots) [0..l-1]+      remaining'         = zipWith (\(i,n) j -> (i,n,j,False)) remaining freeSlots+      allSlots           = L.sortBy (compare `on` \(_,_,x,_) -> x) (fixed ++ remaining')+  return $ map (\(i,n,_,b) -> (i,n,b)) allSlots++-- | Allocate local closures+allocCls :: Maybe JStat -> [(Id, CgStgRhs)] -> G JStat+allocCls dynMiddle xs = do+   (stat, dyn) <- partitionEithers <$> mapM toCl xs+   ac <- allocDynAll True dynMiddle dyn+   pure (mconcat stat <> ac)+  where+    -- left = static, right = dynamic+    toCl :: (Id, CgStgRhs)+         -> G (Either JStat (Ident,JExpr,[JExpr],CostCentreStack))+    -- statics+    {- making zero-arg constructors static is problematic, see #646+       proper candidates for this optimization should have been floated+       already+      toCl (i, StgRhsCon cc con []) = do+      ii <- identForId i+      Left <$> (return (decl ii) <> allocCon ii con cc []) -}+    toCl (i, StgRhsCon cc con _mui _ticjs [a]) | isUnboxableCon con = do+      ii <- identForId i+      ac <- allocCon ii con cc =<< genArg a+      pure (Left (decl ii <> ac))++    -- dynamics+    toCl (i, StgRhsCon cc con _mu _ticks ar) =+      -- fixme do we need to handle unboxed?+      Right <$> ((,,,) <$> identForId i+                       <*> varForDataConWorker con+                       <*> concatMapM genArg ar+                       <*> pure cc)+    toCl (i, cl@(StgRhsClosure _ext cc _upd_flag _args _body)) =+      let live = stgLneLiveExpr cl+      in  Right <$> ((,,,) <$> identForId i+                       <*> varForEntryId i+                       <*> concatMapM varsForId live+                       <*> pure cc)++-- fixme CgCase has a reps_compatible check here+-- | Consume Stg case statement and generate a case statement. See also+-- 'genAlts'+genCase :: HasDebugCallStack+        => ExprCtx+        -> Id+        -> CgStgExpr+        -> AltType+        -> [CgStgAlt]+        -> LiveVars+        -> G (JStat, ExprResult)+genCase ctx bnd e at alts l+  | snd (isInlineExpr (ctxEvaluatedIds ctx) e) = do+      bndi <- identsForId bnd+      let ctx' = ctxSetTop bnd+                  $ ctxSetTarget (assocIdExprs bnd (map toJExpr bndi))+                  $ ctx+      (ej, r) <- genExpr ctx' e+      let d = case r of+                ExprInline d0 -> d0+                ExprCont -> pprPanic "genCase: expression was not inline"+                                     (pprStgExpr panicStgPprOpts e)++      (aj, ar) <- genAlts (ctxAssertEvaluated bnd ctx) bnd at d alts+      (saveCCS,restoreCCS) <- ifProfilingM $ do+        ccsVar <- freshIdent+        pure ( ccsVar ||= toJExpr jCurrentCCS+             , toJExpr jCurrentCCS |= toJExpr ccsVar+             )+      return ( mconcat+          [ mconcat (map decl bndi)+          , saveCCS+          , ej+          , restoreCCS+          , aj+          ]+        , ar+         )+  | otherwise = do+      rj       <- genRet (ctxAssertEvaluated bnd ctx) bnd at alts l+      let ctx' = ctxSetTop bnd+                  $ ctxSetTarget (assocIdExprs bnd (map toJExpr [R1 ..]))+                  $ ctx+      (ej, _r) <- genExpr ctx' e+      return (rj <> ej, ExprCont)++genRet :: HasDebugCallStack+       => ExprCtx+       -> Id+       -> AltType+       -> [CgStgAlt]+       -> LiveVars+       -> G JStat+genRet ctx e at as l = freshIdent >>= f+  where+    allRefs :: [Id]+    allRefs =  S.toList . S.unions $ fmap (exprRefs emptyUFM . alt_rhs) as+    lneLive :: Int+    lneLive    = maximum $ 0 : catMaybes (map (ctxLneBindingStackSize ctx) allRefs)+    ctx'       = ctxLneShrinkStack ctx lneLive+    lneVars    = map fst $ ctxLneFrameVars ctx'+    isLne i    = ctxIsLneBinding ctx i || ctxIsLneLiveVar ctx' i+    nonLne     = filter (not . isLne) (dVarSetElems l)++    f :: Ident -> G JStat+    f r@(TxtI ri)    =  do+      pushLne  <- pushLneFrame lneLive ctx+      saveCCS  <- ifProfilingM $ push [jCurrentCCS]+      free     <- optimizeFree 0 nonLne+      pushRet  <- pushRetArgs free (toJExpr r)+      fun'     <- fun free+      sr       <- genStaticRefs l -- srt+      prof     <- profiling+      emitClosureInfo $+        ClosureInfo r+                    (CIRegs 0 altRegs)+                    ri+                    (fixedLayout . reverse $+                       map (stackSlotType . fst3) free+                       ++ if prof then [ObjV] else map stackSlotType lneVars)+                    CIStackFrame+                    sr+      emitToplevel $ r ||= toJExpr (JFunc [] fun')+      return (pushLne <> saveCCS <> pushRet)+    fst3 ~(x,_,_)  = x++    altRegs :: HasDebugCallStack => [VarType]+    altRegs = case at of+      PrimAlt ptc    -> [primRepVt ptc]+      MultiValAlt _n -> idVt e+      _              -> [PtrV]++    -- special case for popping CCS but preserving stack size+    pop_handle_CCS :: [(JExpr, StackSlot)] -> G JStat+    pop_handle_CCS [] = return mempty+    pop_handle_CCS xs = do+      -- grab the slots from 'xs' and push+      addSlots (map snd xs)+      -- move the stack pointer into the stack by ''length xs + n'+      a <- adjSpN (length xs)+      -- now load from the top of the stack+      return (loadSkip 0 (map fst xs) <> a)++    fun free = resetSlots $ do+      decs          <- declVarsForId e+      load          <- flip assignAll (map toJExpr [R1 ..]) . map toJExpr <$> identsForId e+      loadv         <- verifyRuntimeReps [e]+      ras           <- loadRetArgs free+      rasv          <- verifyRuntimeReps (map (\(x,_,_)->x) free)+      restoreCCS    <- ifProfilingM . pop_handle_CCS $ pure (jCurrentCCS, SlotUnknown)+      rlne          <- popLneFrame False lneLive ctx'+      rlnev         <- verifyRuntimeReps lneVars+      (alts, _altr) <- genAlts ctx' e at Nothing as+      return $ decs <> load <> loadv <> ras <> rasv <> restoreCCS <> rlne <> rlnev <> alts <>+               returnStack++-- | Consume an Stg case alternative and generate the corresponding alternative+-- in JS land. If one alternative is a continuation then we must normalize the+-- other alternatives. See 'Branch' and 'normalizeBranches'.+genAlts :: HasDebugCallStack+        => ExprCtx        -- ^ lhs to assign expression result to+        -> Id             -- ^ id being matched+        -> AltType        -- ^ type+        -> Maybe [JExpr]  -- ^ if known, fields in datacon from earlier expression+        -> [CgStgAlt]     -- ^ the alternatives+        -> G (JStat, ExprResult)+genAlts ctx e at me alts = do+  (st, er) <- case at of++    PolyAlt -> case alts of+      [alt] -> (branch_stat &&& branch_result) <$> mkAlgBranch ctx e alt+      _     -> panic "genAlts: multiple polyalt"++    PrimAlt _tc+      | [GenStgAlt _ bs expr] <- alts+      -> do+        ie       <- varsForId e+        dids     <- mconcat <$> mapM declVarsForId bs+        bss      <- concatMapM varsForId bs+        (ej, er) <- genExpr ctx expr+        return (dids <> assignAll bss ie <> ej, er)++    PrimAlt tc+      -> do+        ie <- varsForId e+        (r, bss) <- normalizeBranches ctx <$>+           mapM (isolateSlots . mkPrimIfBranch ctx [primRepVt tc]) alts+        setSlots []+        return (mkSw ie bss, r)++    MultiValAlt n+      | [GenStgAlt _ bs expr] <- alts+      -> do+        eids     <- varsForId e+        l        <- loadUbxTup eids bs n+        (ej, er) <- genExpr ctx expr+        return (l <> ej, er)++    AlgAlt tc+      | [_alt] <- alts+      , isUnboxedTupleTyCon tc+      -> panic "genAlts: unexpected unboxed tuple"++    AlgAlt _tc+      | Just es <- me+      , [GenStgAlt (DataAlt dc) bs expr] <- alts+      , not (isUnboxableCon dc)+      -> do+        bsi <- mapM identsForId bs+        (ej, er) <- genExpr ctx expr+        return (declAssignAll (concat bsi) es <> ej, er)++    AlgAlt _tc+      | [alt] <- alts+      -> do+        Branch _ s r <- mkAlgBranch ctx e alt+        return (s, r)++    AlgAlt _tc+      | [alt,_] <- alts+      , DataAlt dc <- alt_con alt+      , isBoolDataCon dc+      -> do+        i <- varForId e+        nbs <- normalizeBranches ctx <$>+            mapM (isolateSlots . mkAlgBranch ctx e) alts+        case nbs of+          (r, [Branch _ s1 _, Branch _ s2 _]) -> do+            let s = if   dataConTag dc == 2+                    then IfStat i s1 s2+                    else IfStat i s2 s1+            setSlots []+            return (s, r)+          _ -> error "genAlts: invalid branches for Bool"++    AlgAlt _tc -> do+        ei <- varForId e+        (r, brs) <- normalizeBranches ctx <$>+            mapM (isolateSlots . mkAlgBranch ctx e) alts+        setSlots []+        return (mkSwitch (ei .^ "f" .^ "a") brs, r)++    _ -> pprPanic "genAlts: unhandled case variant" (ppr (at, length alts))++  ver <- verifyMatchRep e at+  pure (ver <> st, er)++-- | If 'StgToJSConfig.csRuntimeAssert' is set, then generate an assertion that+-- asserts the pattern match is valid, e.g., the match is attempted on a+-- Boolean, a Data Constructor, or some number.+verifyMatchRep :: HasDebugCallStack => Id -> AltType -> G JStat+verifyMatchRep x alt = do+  runtime_assert <- csRuntimeAssert <$> getSettings+  if not runtime_assert+    then pure mempty+    else case alt of+      AlgAlt tc -> do+        ix <- varsForId x+        pure $ ApplStat (var "h$verify_match_alg") (ValExpr(JStr(mkFastString (renderWithContext defaultSDocContext (ppr tc)))):ix)+      _ -> pure mempty++-- | A 'Branch' represents a possible branching path of an Stg case statement,+-- i.e., a possible code path from an 'StgAlt'+data Branch a = Branch+  { branch_expr   :: a+  , branch_stat   :: JStat+  , branch_result :: ExprResult+  }+  deriving (Eq,Functor)++-- | If one branch ends in a continuation but another is inline, we need to+-- adjust the inline branch to use the continuation convention+normalizeBranches :: ExprCtx+                  -> [Branch a]+                  -> (ExprResult, [Branch a])+normalizeBranches ctx brs+    | all (==ExprCont) (fmap branch_result brs) =+        (ExprCont, brs)+    | branchResult (fmap branch_result brs) == ExprCont =+        (ExprCont, map mkCont brs)+    | otherwise =+        (ExprInline Nothing, brs)+  where+    mkCont b = case branch_result b of+      ExprInline{} -> b { branch_stat   = branch_stat b <> assignAll jsRegsFromR1+                                                                     (concatMap typex_expr $ ctxTarget ctx)+                        , branch_result = ExprCont+                        }+      _ -> b++-- | Load an unboxed tuple. "Loading" means getting all 'Idents' from the input+-- ID's, declaring them as variables in JS land and binding them, in order, to+-- 'es'.+loadUbxTup :: [JExpr] -> [Id] -> Int -> G JStat+loadUbxTup es bs _n = do+  bs' <- concatMapM identsForId bs+  return $ declAssignAll bs' es++mkSw :: [JExpr] -> [Branch (Maybe [JExpr])] -> JStat+mkSw [e] cases = mkSwitch e (fmap (fmap (fmap head)) cases)+mkSw es cases  = mkIfElse es cases++-- | Switch for pattern matching on constructors or prims+mkSwitch :: JExpr -> [Branch (Maybe JExpr)] -> JStat+mkSwitch e cases+  | [Branch (Just c1) s1 _] <- n+  , [Branch _ s2 _] <- d+  = IfStat (InfixExpr StrictEqOp e c1) s1 s2++  | [Branch (Just c1) s1 _, Branch _ s2 _] <- n+  , null d+  = IfStat (InfixExpr StrictEqOp e c1) s1 s2++  | null d+  = SwitchStat e (map addBreak (init n)) (branch_stat (last n))++  | [Branch _ d0 _] <- d+  = SwitchStat e (map addBreak n) d0++  | otherwise = panic "mkSwitch: multiple default cases"+  where+    addBreak (Branch (Just c) s _) = (c, mconcat [s, BreakStat Nothing])+    addBreak _                     = panic "mkSwitch: addBreak"+    (n,d) = L.partition (isJust . branch_expr) cases++-- | if/else for pattern matching on things that js cannot switch on+-- the list of branches is expected to have the default alternative+-- first, if it exists+mkIfElse :: [JExpr] -> [Branch (Maybe [JExpr])] -> JStat+mkIfElse e s = go (L.reverse s)+    where+      go = \case+        [Branch _ s _]              -> s -- only one 'nothing' allowed+        (Branch (Just e0) s _ : xs) -> IfStat (mkEq e e0) s (go xs)+        [] -> panic "mkIfElse: empty expression list"+        _  -> panic "mkIfElse: multiple DEFAULT cases"++-- | Wrapper to contruct sequences of (===), e.g.,+--+-- > mkEq [l0,l1,l2] [r0,r1,r2] = (l0 === r0) && (l1 === r1) && (l2 === r2)+--+mkEq :: [JExpr] -> [JExpr] -> JExpr+mkEq es1 es2+  | length es1 == length es2 = foldl1 (InfixExpr LAndOp) (zipWith (InfixExpr StrictEqOp) es1 es2)+  | otherwise                = panic "mkEq: incompatible expressions"++mkAlgBranch :: ExprCtx   -- ^ toplevel id for the result+            -> Id        -- ^ datacon to match+            -> CgStgAlt  -- ^ match alternative with binders+            -> G (Branch (Maybe JExpr))+mkAlgBranch top d alt+  | DataAlt dc <- alt_con alt+  , isUnboxableCon dc+  , [b] <- alt_bndrs alt+  = do+    idd  <- varForId d+    fldx <- identsForId b+    case fldx of+      [fld] -> do+        (ej, er) <- genExpr top (alt_rhs alt)+        return (Branch Nothing (mconcat [fld ||= idd, ej]) er)+      _ -> panic "mkAlgBranch: invalid size"++  | otherwise+  = do+    cc       <- caseCond (alt_con alt)+    idd      <- varForId d+    b        <- loadParams idd (alt_bndrs alt)+    (ej, er) <- genExpr top (alt_rhs alt)+    return (Branch cc (b <> ej) er)++-- | Generate a primitive If-expression+mkPrimIfBranch :: ExprCtx+               -> [VarType]+               -> CgStgAlt+               -> G (Branch (Maybe [JExpr]))+mkPrimIfBranch top _vt alt =+  (\ic (ej,er) -> Branch ic ej er) <$> ifCond (alt_con alt) <*> genExpr top (alt_rhs alt)++-- fixme are bool things always checked correctly here?+ifCond :: AltCon -> G (Maybe [JExpr])+ifCond = \case+  DataAlt da -> return $ Just [toJExpr (dataConTag da)]+  LitAlt l   -> Just <$> genLit l+  DEFAULT    -> return Nothing++caseCond :: AltCon -> G (Maybe JExpr)+caseCond = \case+  DEFAULT    -> return Nothing+  DataAlt da -> return $ Just (toJExpr $ dataConTag da)+  LitAlt l   -> genLit l >>= \case+    [e] -> pure (Just e)+    es  -> pprPanic "caseCond: expected single-variable literal" (ppr es)++-- fixme use single tmp var for all branches+-- | Load parameters from constructor+loadParams :: JExpr -> [Id] -> G JStat+loadParams from args = do+  as <- concat <$> zipWithM (\a u -> map (,u) <$> identsForId a) args use+  return $ case as of+    []                 -> mempty+    [(x,u)]            -> loadIfUsed (from .^ closureField1_) x  u+    [(x1,u1),(x2,u2)]  -> mconcat+                            [ loadIfUsed (from .^ closureField1_) x1 u1+                            , loadIfUsed (from .^ closureField2_) x2 u2+                            ]+    ((x,u):xs)         -> mconcat+                            [ loadIfUsed (from .^ closureField1_) x u+                            , jVar (\d -> mconcat [ d |= from .^ closureField2_+                                                  , loadConVarsIfUsed d xs+                                                  ])+                            ]+  where+    use = repeat True -- fixme clean up+    loadIfUsed fr tgt True = tgt ||= fr+    loadIfUsed  _ _   _    = mempty++    loadConVarsIfUsed fr cs = mconcat $ zipWith f cs [(1::Int)..]+      where f (x,u) n = loadIfUsed (SelExpr fr (TxtI (dataFieldName n))) x u++-- | Determine if a branch will end in a continuation or not. If not the inline+-- branch must be normalized. See 'normalizeBranches'+-- NB. not a Monoid+branchResult :: HasDebugCallStack => [ExprResult] -> ExprResult+branchResult = \case+  []                   -> panic "branchResult: empty list"+  [e]                  -> e+  (ExprCont:_)         -> ExprCont+  (_:es)+    | elem ExprCont es -> ExprCont+    | otherwise        -> ExprInline Nothing++-- | Push return arguments onto the stack. The 'Bool' tracks whether the value+-- is already on the stack or not, used in 'StgToJS.Stack.pushOptimized'.+pushRetArgs :: HasDebugCallStack => [(Id,Int,Bool)] -> JExpr -> G JStat+pushRetArgs free fun = do+  rs <- mapM (\(i,n,b) -> (\es->(es!!(n-1),b)) <$> genIdArg i) free+  pushOptimized (rs++[(fun,False)])++-- | Load the return arguments then pop the stack frame+loadRetArgs :: HasDebugCallStack => [(Id,Int,Bool)] -> G JStat+loadRetArgs free = do+  ids <- mapM (\(i,n,_b) -> (!! (n-1)) <$> genIdStackArgI i) free+  popSkipI 1 ids++-- | allocate multiple, possibly mutually recursive, closures+allocDynAll :: Bool -> Maybe JStat -> [(Ident,JExpr,[JExpr],CostCentreStack)] -> G JStat+{-+XXX remove use of template and enable in-place init again+allocDynAll haveDecl middle [(to,entry,free,cc)]+  | isNothing middle && to `notElem` (free ^.. template) = do+      ccs <- ccsVarJ cc+      return $ allocDynamic s haveDecl to entry free ccs -}+allocDynAll haveDecl middle cls = do+  settings <- getSettings+  let+    middle' = fromMaybe mempty middle++    decl_maybe i e+      | haveDecl  = toJExpr i |= e+      | otherwise = i ||= e++    makeObjs :: G JStat+    makeObjs =+      fmap mconcat $ forM cls $ \(i,f,_,cc) -> do+      ccs <- maybeToList <$> costCentreStackLbl cc+      pure $ mconcat+        [ decl_maybe i $ if csInlineAlloc settings+            then ValExpr (jhFromList $ [ (closureEntry_ , f)+                                       , (closureField1_, null_)+                                       , (closureField2_, null_)+                                       , (closureMeta_  , zero_)+                                       ]+                             ++ fmap (\cid -> ("cc", ValExpr (JVar cid))) ccs)+            else ApplExpr (var "h$c") (f : fmap (ValExpr . JVar) ccs)+        ]++    fillObjs = mconcat $ map fillObj cls+    fillObj (i,_,es,_)+      | csInlineAlloc settings || length es > 24 =+          case es of+            []      -> mempty+            [ex]    -> toJExpr i .^ closureField1_ |= toJExpr ex+            [e1,e2] -> mconcat+                        [ toJExpr i .^ closureField1_ |= toJExpr e1+                        , toJExpr i .^ closureField2_ |= toJExpr e2+                        ]+            (ex:es)  -> mconcat+                        [ toJExpr i .^ closureField1_ |= toJExpr ex+                        , toJExpr i .^ closureField2_ |= toJExpr (jhFromList (zip dataFieldNames es))+                        ]+      | otherwise = case es of+            []      -> mempty+            [ex]    -> toJExpr i .^ closureField1_ |= ex+            [e1,e2] -> mconcat+                        [ toJExpr i .^ closureField1_ |= e1+                        , toJExpr i .^ closureField2_ |= e2+                        ]+            (ex:es)  -> mconcat+                        [ toJExpr i .^ closureField1_ |= ex+                        , toJExpr i .^ closureField2_ |= fillFun es+                        ]++    fillFun [] = null_+    fillFun es = ApplExpr (allocData (length es)) es++    checkObjs | csAssertRts settings  = mconcat $+                map (\(i,_,_,_) -> ApplStat (ValExpr (JVar (TxtI "h$checkObj"))) [toJExpr i]) cls+              | otherwise = mempty++  objs <- makeObjs+  pure $ mconcat [objs, middle', fillObjs, checkObjs]++-- | Generate a primop. This function wraps around the real generator+-- 'GHC.StgToJS.genPrim', handling the 'ExprCtx' and all arguments before+-- generating the primop.+genPrimOp :: ExprCtx -> PrimOp -> [StgArg] -> Type -> G (JStat, ExprResult)+genPrimOp ctx op args t = do+  as <- concatMapM genArg args+  prof <- csProf <$> getSettings+  bound <- csBoundsCheck <$> getSettings+  -- fixme: should we preserve/check the primreps?+  return $ case genPrim prof bound t op (concatMap typex_expr $ ctxTarget ctx) as of+             PrimInline s -> (s, ExprInline Nothing)+             PRPrimCall s -> (s, ExprCont)
+ compiler/GHC/StgToJS/ExprCtx.hs view
@@ -0,0 +1,172 @@+{-# LANGUAGE TupleSections #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.ExprCtx+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+-- TODO: Write my description!+-----------------------------------------------------------------------------++module GHC.StgToJS.ExprCtx+  ( ExprCtx+  , initExprCtx+  , ctxAssertEvaluated+  , ctxIsEvaluated+  , ctxSetSrcSpan+  , ctxSrcSpan+  , ctxSetTop+  , ctxTarget+  , ctxSetTarget+  , ctxEvaluatedIds+  -- * Let-no-escape+  , ctxClearLneFrame+  , ctxUpdateLneFrame+  , ctxLneFrameVars+  , ctxLneFrameSize+  , ctxIsLneBinding+  , ctxIsLneLiveVar+  , ctxLneBindingStackSize+  , ctxLneShrinkStack+  )+where++import GHC.Prelude++import GHC.StgToJS.Types++import GHC.Types.Unique.FM+import GHC.Types.Unique.Set+import GHC.Types.Var+import GHC.Types.SrcLoc++import GHC.Utils.Outputable+import GHC.Utils.Panic++import Data.Maybe+++-- | Context into which an expression is evaluated+data ExprCtx = ExprCtx+  { ctxTop        :: Id+    -- ^ Top-level binding Id++  , ctxTarget     :: [TypedExpr]+    -- ^ Target variables for the evaluated expression++  , ctxEvaluatedIds :: UniqSet Id+    -- ^ Ids that we know to be evaluated (e.g. case binders when the expression+    -- to evaluate is in an alternative)++  , ctxSrcSpan    :: Maybe RealSrcSpan+    -- ^ Source location++  ----------------------------+  -- Handling of let-no-escape++  , ctxLneFrameBs :: UniqFM Id Int+    -- ^ LNE bindings with their expected stack size.+    --+    -- The Int is the size of the stack when the LNE binding was defined.+    -- We need to shrink the stack back to this size when we enter one of the+    -- associated binder rhs: it expects its free variables at certain offsets+    -- in the stack.++  , ctxLneFrameVars :: [(Id,Int)]+    -- ^ Contents of current LNE frame+    --+    -- Variables and their index on the stack++  , ctxLneFrameSize :: {-# UNPACK #-} !Int+    -- ^ Cache the length of `ctxLneFrameVars`++  }++-- | Initialize an expression context in the context of the given top-level+-- binding Id+initExprCtx :: Id -> ExprCtx+initExprCtx i = ExprCtx+  { ctxTop          = i+  , ctxTarget       = []+  , ctxEvaluatedIds = emptyUniqSet+  , ctxLneFrameBs   = emptyUFM+  , ctxLneFrameVars = []+  , ctxLneFrameSize = 0+  , ctxSrcSpan      = Nothing+  }++-- | Set target+ctxSetTarget :: [TypedExpr] -> ExprCtx -> ExprCtx+ctxSetTarget t ctx = ctx { ctxTarget = t }++-- | Set top-level binding Id+ctxSetTop :: Id -> ExprCtx -> ExprCtx+ctxSetTop i ctx = ctx { ctxTop = i }++-- | Add an Id to the known-evaluated set+ctxAssertEvaluated :: Id -> ExprCtx -> ExprCtx+ctxAssertEvaluated i ctx = ctx { ctxEvaluatedIds = addOneToUniqSet (ctxEvaluatedIds ctx) i }++-- | Set source location+ctxSetSrcSpan :: RealSrcSpan -> ExprCtx -> ExprCtx+ctxSetSrcSpan span ctx = ctx { ctxSrcSpan = Just span }++-- | Update let-no-escape frame+ctxUpdateLneFrame :: [(Id,Int)] -> [Id] -> ExprCtx -> ExprCtx+ctxUpdateLneFrame new_spilled_vars new_lne_ids ctx =+  let old_frame_size = ctxLneFrameSize ctx+      new_frame_size = old_frame_size + length new_spilled_vars+  in ctx+    { ctxLneFrameBs   = addListToUFM (ctxLneFrameBs ctx) (map (,new_frame_size) new_lne_ids)+    , ctxLneFrameSize = new_frame_size+    , ctxLneFrameVars = ctxLneFrameVars ctx ++ new_spilled_vars+    }++-- | Remove information about the current LNE frame+ctxClearLneFrame :: ExprCtx -> ExprCtx+ctxClearLneFrame ctx =+  ctx+    { ctxLneFrameBs   = emptyUFM+    , ctxLneFrameVars = []+    , ctxLneFrameSize = 0+    }++-- | Predicate: do we know for sure that the given Id is evaluated?+ctxIsEvaluated :: ExprCtx -> Id -> Bool+ctxIsEvaluated ctx i = i `elementOfUniqSet` ctxEvaluatedIds ctx++-- | Does the given Id correspond to a LNE binding+ctxIsLneBinding :: ExprCtx -> Id -> Bool+ctxIsLneBinding ctx i = isJust (ctxLneBindingStackSize ctx i)++-- | Does the given Id correspond to a LNE live var on the stack+ctxIsLneLiveVar :: ExprCtx -> Id -> Bool+ctxIsLneLiveVar ctx i = i `elem` map fst (ctxLneFrameVars ctx)++-- | Return the LNE stack size associated to the given Id.+-- Return Nothing when the Id doesn't correspond to a LNE binding.+ctxLneBindingStackSize :: ExprCtx -> Id -> Maybe Int+ctxLneBindingStackSize ctx i = lookupUFM (ctxLneFrameBs ctx) i++-- | Shrink the LNE stack to the given size+ctxLneShrinkStack :: ExprCtx -> Int -> ExprCtx+ctxLneShrinkStack ctx n =+  let l = ctxLneFrameSize ctx+  in assertPpr+      (l >= n)+      (vcat [ text "ctxLneShrinkStack: let-no-escape stack too short:"+            , ppr l+            , text " < "+            , ppr n+            ])+      (ctx { ctxLneFrameVars = take n (ctxLneFrameVars ctx)+           , ctxLneFrameSize = n+           }+      )
+ compiler/GHC/StgToJS/FFI.hs view
@@ -0,0 +1,352 @@+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE OverloadedStrings #-}++module GHC.StgToJS.FFI+  ( genPrimCall+  , genForeignCall+  , saturateFFI+  )+where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Make+import GHC.JS.Transform++import GHC.StgToJS.Arg+import GHC.StgToJS.ExprCtx+import GHC.StgToJS.Monad+import GHC.StgToJS.Types+import GHC.StgToJS.Literal+import GHC.StgToJS.Regs+import GHC.StgToJS.CoreUtils+import GHC.StgToJS.Ids++import GHC.Types.RepType+import GHC.Types.ForeignCall+import GHC.Types.Unique.Map+import GHC.Types.Unique.FM++import GHC.Stg.Syntax++import GHC.Builtin.PrimOps+import GHC.Builtin.Types.Prim++import GHC.Core.Type hiding (typeSize)++import GHC.Utils.Misc+import GHC.Utils.Panic+import GHC.Utils.Outputable (renderWithContext, defaultSDocContext, ppr, vcat, text)+import GHC.Data.FastString++import Data.Char+import Data.Monoid+import Data.Maybe+import qualified Data.List as L+import Control.Monad+import Control.Applicative+import qualified Text.ParserCombinators.ReadP as P++genPrimCall :: ExprCtx -> PrimCall -> [StgArg] -> Type -> G (JStat, ExprResult)+genPrimCall ctx (PrimCall lbl _) args t = do+  j <- parseFFIPattern False False False ("h$" ++ unpackFS lbl) t (concatMap typex_expr $ ctxTarget ctx) args+  return (j, ExprInline Nothing)++-- | generate the actual call+{-+  parse FFI patterns:+   "&value         -> value+  1. "function"      -> ret = function(...)+  2. "$r = $1.f($2)  -> r1 = a1.f(a2)++  arguments, $1, $2, $3 unary arguments+     $1_1, $1_2, for a binary argument++  return type examples+  1. $r                      unary return+  2. $r1, $r2                binary return+  3. $r1, $r2, $r3_1, $r3_2  unboxed tuple return+ -}+parseFFIPattern :: Bool  -- ^ catch exception and convert them to haskell exceptions+                -> Bool  -- ^ async (only valid with javascript calling conv)+                -> Bool  -- ^ using javascript calling convention+                -> String+                -> Type+                -> [JExpr]+                -> [StgArg]+                -> G JStat+parseFFIPattern catchExcep async jscc pat t es as+  | catchExcep = do+      c <- parseFFIPatternA async jscc pat t es as+      -- Generate:+      --  try {+      --    `c`;+      --  } catch(except) {+      --    return h$throwJSException(except);+      --  }+      let ex = TxtI "except"+      return (TryStat c ex (ReturnStat (ApplExpr (var "h$throwJSException") [toJExpr ex])) mempty)+  | otherwise  = parseFFIPatternA async jscc pat t es as++parseFFIPatternA :: Bool  -- ^ async+                 -> Bool  -- ^ using JavaScript calling conv+                 -> String+                 -> Type+                 -> [JExpr]+                 -> [StgArg]+                 -> G JStat+-- async calls get an extra callback argument+-- call it with the result+parseFFIPatternA True True pat t es as  = do+  cb <- freshIdent+  x  <- freshIdent+  d  <- freshIdent+  stat <- parseFFIPattern' (Just (toJExpr cb)) True pat t es as+  return $ mconcat+    [ x  ||= (toJExpr (jhFromList [("mv", null_)]))+    , cb ||= ApplExpr (var "h$mkForeignCallback") [toJExpr x]+    , stat+    , IfStat (InfixExpr StrictEqOp (toJExpr x .^ "mv") null_)+          (mconcat+            [ toJExpr x .^ "mv" |= UOpExpr NewOp (ApplExpr (var "h$MVar") [])+            , sp |= Add sp one_+            , (IdxExpr stack sp) |= var "h$unboxFFIResult"+            , ReturnStat $ ApplExpr (var "h$takeMVar") [toJExpr x .^ "mv"]+            ])+          (mconcat+            [ d ||= toJExpr x .^ "mv"+            , copyResult (toJExpr d)+            ])+    ]+    where nrst = typeSize t+          copyResult d = assignAllEqual es (map (IdxExpr d . toJExpr) [0..nrst-1])+parseFFIPatternA _async javascriptCc pat t es as =+  parseFFIPattern' Nothing javascriptCc pat t es as++-- parseFFIPatternA _ _ _ _ _ _ = error "parseFFIPattern: non-JavaScript pattern must be synchronous"++parseFFIPattern' :: Maybe JExpr -- ^ Nothing for sync, Just callback for async+                 -> Bool        -- ^ javascript calling convention used+                 -> String      -- ^ pattern called+                 -> Type        -- ^ return type+                 -> [JExpr]     -- ^ expressions to return in (may be more than necessary)+                 -> [StgArg]    -- ^ arguments+                 -> G JStat+parseFFIPattern' callback javascriptCc pat t ret args+  | not javascriptCc = mkApply pat+  | otherwise =+   if True+     then mkApply pat+     else do+      u <- freshUnique+      case parseFfiJME pat u of+        Right (ValExpr (JVar (TxtI _ident))) -> mkApply pat+        Right expr | not async && length tgt < 2 -> do+          (statPre, ap) <- argPlaceholders javascriptCc args+          let rp  = resultPlaceholders async t ret+              env = addListToUFM emptyUFM (rp ++ ap)+          if length tgt == 1+            then return $ statPre <> (mapStatIdent (replaceIdent env) (var "$r" |= expr))+            else return $ statPre <> (mapStatIdent (replaceIdent env) (toStat expr))+        Right _ -> p $ "invalid expression FFI pattern. Expression FFI patterns can only be used for synchronous FFI " +++                       " imports with result size 0 or 1.\n" ++ pat+        Left _ -> case parseFfiJM pat u of+          Left err -> p (show err)+          Right stat -> do+            let rp = resultPlaceholders async t ret+            let cp = callbackPlaceholders callback+            (statPre, ap) <- argPlaceholders javascriptCc args+            let env = addListToUFM emptyUFM (rp ++ ap ++ cp)+            return $ statPre <> (mapStatIdent (replaceIdent env) stat) -- fixme trace?+  where+    async = isJust callback+    tgt = take (typeSize t) ret+    -- automatic apply, build call and result copy+    mkApply f+      | Just cb <- callback = do+         (stats, as) <- unzip <$> mapM (genFFIArg javascriptCc) args+         cs <- getSettings+         return $ traceCall cs as <> mconcat stats <> ApplStat f' (concat as++[cb])+      | {-ts@-}+        (t:ts') <- tgt = do+         (stats, as) <- unzip <$> mapM (genFFIArg javascriptCc) args+         cs <- getSettings+         return $ traceCall cs as+                <> mconcat stats+                <> (t |= ApplExpr f' (concat as) )+                <> copyResult ts'+           -- _ -> error "mkApply: empty list"+      | otherwise = do+         (stats, as) <- unzip <$> mapM (genFFIArg javascriptCc) args+         cs <- getSettings+         return $ traceCall cs as <> mconcat stats <> ApplStat f' (concat as)+        where f' = toJExpr (TxtI $ mkFastString f)+    copyResult rs = mconcat $ zipWith (\t r -> toJExpr r |= toJExpr t) (enumFrom Ret1) rs+    p e = error ("Parse error in FFI pattern: " ++ pat ++ "\n" ++ e)++    replaceIdent :: UniqFM Ident JExpr -> Ident -> JExpr+    replaceIdent env i+      | isFFIPlaceholder i = fromMaybe err (lookupUFM env i)+      | otherwise = ValExpr (JVar i)+        where+          (TxtI i') = i+          err = pprPanic "parseFFIPattern': invalid placeholder, check function type"+                  (vcat [text pat, ppr i', ppr args, ppr t])+    traceCall cs as+        | csTraceForeign cs = ApplStat (var "h$traceForeign") [toJExpr pat, toJExpr as]+        | otherwise         = mempty++-- ident is $N, $N_R, $rN, $rN_R or $r or $c+isFFIPlaceholder :: Ident -> Bool+isFFIPlaceholder (TxtI x) = not (null (P.readP_to_S parser (unpackFS x)))+  where+    digit = P.satisfy (`elem` ("0123456789" :: String))+    parser = void (P.string "$r" >> P.eof) <|>+             void (P.string "$c" >> P.eof) <|> do+      _ <- P.char '$'+      P.optional (P.char 'r')+      _ <- P.many1 digit+      P.optional (P.char '_' >> P.many1 digit)+      P.eof++-- generate arg to be passed to FFI call, with marshalling JStat to be run+-- before the call+genFFIArg :: Bool -> StgArg -> G (JStat, [JExpr])+genFFIArg _isJavaScriptCc (StgLitArg l) = (mempty,) <$> genLit l+genFFIArg isJavaScriptCc a@(StgVarArg i)+    | not isJavaScriptCc &&+      (tycon == byteArrayPrimTyCon || tycon == mutableByteArrayPrimTyCon) =+        (\x -> (mempty,[x, zero_])) <$> varForId i+    | isVoid r                  = return (mempty, [])+--    | Just x <- marshalFFIArg a = x+    | isMultiVar r              = (mempty,) <$> mapM (varForIdN i) [1..varSize r]+    | otherwise                 = (\x -> (mempty,[x])) <$> varForId i+   where+     tycon  = tyConAppTyCon (unwrapType arg_ty)+     arg_ty = stgArgType a+     r      = uTypeVt arg_ty++-- $1, $2, $3 for single, $1_1, $1_2 etc for dual+-- void args not counted+argPlaceholders :: Bool -> [StgArg] -> G (JStat, [(Ident,JExpr)])+argPlaceholders isJavaScriptCc args = do+  (stats, idents0) <- unzip <$> mapM (genFFIArg isJavaScriptCc) args+  let idents = filter (not . null) idents0+  return $ (mconcat stats, concat+    (zipWith (\is n -> mkPlaceholder True ("$"++show n) is) idents [(1::Int)..]))++mkPlaceholder :: Bool -> String -> [JExpr] -> [(Ident, JExpr)]+mkPlaceholder undersc prefix aids =+      case aids of+             []       -> []+             [x]      -> [(TxtI . mkFastString $ prefix, x)]+             xs@(x:_) -> (TxtI . mkFastString $ prefix, x) :+                zipWith (\x m -> (TxtI . mkFastString $ prefix ++ u ++ show m,x)) xs [(1::Int)..]+   where u = if undersc then "_" else ""++-- $r for single, $r1,$r2 for dual+-- $r1, $r2, etc for ubx tup, void args not counted+resultPlaceholders :: Bool -> Type -> [JExpr] -> [(Ident,JExpr)] -- ident, replacement+resultPlaceholders True _ _ = [] -- async has no direct resuls, use callback+resultPlaceholders False t rs =+  case typeVt (unwrapType t) of+    [t'] -> mkUnary (varSize t')+    uts ->+      let sizes = filter (>0) (map varSize uts)+          f _ 0 = []+          f n 1 = [["$r" ++ show n]]+          f n k = ["$r" ++ sn, "$r" ++ sn ++ "_1"] : map (\x -> ["$r" ++ sn ++ "_" ++ show x]) [2..k]+            where sn = show n+          phs   = zipWith (\size n -> f n size) sizes [(1::Int)..]+      in case sizes of+           [n] -> mkUnary n+           _   -> concat $ zipWith (\phs' r -> map (\i -> (TxtI (mkFastString i), r)) phs') (concat phs) rs+  where+    mkUnary 0 = []+    mkUnary 1 = [(TxtI "$r",head rs)] -- single+    mkUnary n = [(TxtI "$r",head rs),(TxtI "$r1", head rs)] +++       zipWith (\n r -> (TxtI . mkFastString $ "$r" ++ show n, toJExpr r)) [2..n] (tail rs)++callbackPlaceholders :: Maybe JExpr -> [(Ident,JExpr)]+callbackPlaceholders Nothing  = []+callbackPlaceholders (Just e) = [((TxtI "$c"), e)]++parseFfiJME :: String -> Int -> Either String JExpr+parseFfiJME _xs _u =  Left "parseFfiJME not yet implemented"++parseFfiJM :: String -> Int -> Either String JStat+parseFfiJM _xs _u = Left "parseFfiJM not yet implemented"++saturateFFI :: JMacro a => Int -> a -> a+saturateFFI u = jsSaturate (Just . mkFastString $ "ghcjs_ffi_sat_" ++ show u)++genForeignCall :: HasDebugCallStack+               => ExprCtx+               -> ForeignCall+               -> Type+               -> [JExpr]+               -> [StgArg]+               -> G (JStat, ExprResult)+genForeignCall _ctx+               (CCall (CCallSpec (StaticTarget _ tgt Nothing True)+                                   JavaScriptCallConv+                                   PlayRisky))+               _t+               [obj]+               args+  | tgt == fsLit "h$buildObject"+  , Just pairs <- getObjectKeyValuePairs args = do+      pairs' <- mapM (\(k,v) -> genArg v >>= \vs -> return (k, head vs)) pairs+      return ( (|=) obj (ValExpr (JHash $ listToUniqMap pairs'))+             , ExprInline Nothing+             )++genForeignCall ctx (CCall (CCallSpec ccTarget cconv safety)) t tgt args = do+  emitForeign (ctxSrcSpan ctx) (mkFastString lbl) safety cconv (map showArgType args) (showType t)+  (,exprResult) <$> parseFFIPattern catchExcep async isJsCc lbl t tgt' args+  where+    isJsCc = cconv == JavaScriptCallConv++    lbl | (StaticTarget _ clbl _mpkg _isFunPtr) <- ccTarget+            = let clbl' = unpackFS clbl+              in  if | isJsCc -> clbl'+                     | wrapperPrefix `L.isPrefixOf` clbl' ->+                         ("h$" ++ (drop 2 $ dropWhile isDigit $ drop (length wrapperPrefix) clbl'))+                     | otherwise -> "h$" ++ clbl'+        | otherwise = "h$callDynamic"++    exprResult | async     = ExprCont+               | otherwise = ExprInline Nothing++    catchExcep = (cconv == JavaScriptCallConv) &&+                 playSafe safety || playInterruptible safety++    async | isJsCc    = playInterruptible safety+          | otherwise = playInterruptible safety || playSafe safety++    tgt'  | async     = take (length tgt) jsRegsFromR1+          | otherwise = tgt++    wrapperPrefix = "ghczuwrapperZC"++getObjectKeyValuePairs :: [StgArg] -> Maybe [(FastString, StgArg)]+getObjectKeyValuePairs [] = Just []+getObjectKeyValuePairs (k:v:xs)+  | Just t <- argJSStringLitUnfolding k =+      fmap ((t,v):) (getObjectKeyValuePairs xs)+getObjectKeyValuePairs _ = Nothing++argJSStringLitUnfolding :: StgArg -> Maybe FastString+argJSStringLitUnfolding (StgVarArg _v) = Nothing -- fixme+argJSStringLitUnfolding _              = Nothing++showArgType :: StgArg -> FastString+showArgType a = showType (stgArgType a)++showType :: Type -> FastString+showType t+  | Just tc <- tyConAppTyCon_maybe (unwrapType t) =+      mkFastString (renderWithContext defaultSDocContext (ppr tc))+  | otherwise = "<unknown>"
+ compiler/GHC/StgToJS/Heap.hs view
@@ -0,0 +1,155 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-}++module GHC.StgToJS.Heap+  ( closureType+  , entryClosureType+  , isObject+  , isThunk+  , isThunk'+  , isBlackhole+  , isFun+  , isFun'+  , isPap+  , isPap'+  , isCon+  , isCon'+  , conTag+  , conTag'+  , closureEntry+  , closureMeta+  , closureField1+  , closureField2+  , closureCC+  , funArity+  , funArity'+  , papArity+  , funOrPapArity+  -- * Field names+  , closureEntry_+  , closureMeta_+  , closureCC_+  , closureField1_+  , closureField2_+  -- * Javascript Type literals+  , jTyObject+  )+where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Make+import GHC.StgToJS.Types+import GHC.Data.FastString++closureEntry_ :: FastString+closureEntry_ = "f"++closureField1_ :: FastString+closureField1_ = "d1"++closureField2_ :: FastString+closureField2_ = "d2"++closureMeta_ :: FastString+closureMeta_ = "m"++closureCC_ :: FastString+closureCC_ = "cc"++entryClosureType_ :: FastString+entryClosureType_ = "t"++entryConTag_ :: FastString+entryConTag_ = "a"++entryFunArity_ :: FastString+entryFunArity_ = "a"++jTyObject :: JExpr+jTyObject = jString "object"++closureType :: JExpr -> JExpr+closureType = entryClosureType . closureEntry++entryClosureType :: JExpr -> JExpr+entryClosureType f = f .^ entryClosureType_++isObject :: JExpr -> JExpr+isObject c = typeof c .===. String "object"++isThunk :: JExpr -> JExpr+isThunk c = closureType c .===. toJExpr Thunk++isThunk' :: JExpr -> JExpr+isThunk' f = entryClosureType f .===. toJExpr Thunk++isBlackhole :: JExpr -> JExpr+isBlackhole c = closureType c .===. toJExpr Blackhole++isFun :: JExpr -> JExpr+isFun c = closureType c .===. toJExpr Fun++isFun' :: JExpr -> JExpr+isFun' f = entryClosureType f .===. toJExpr Fun++isPap :: JExpr -> JExpr+isPap c = closureType c .===. toJExpr Pap++isPap' :: JExpr -> JExpr+isPap' f = entryClosureType f .===. toJExpr Pap++isCon :: JExpr -> JExpr+isCon c = closureType c .===. toJExpr Con++isCon' :: JExpr -> JExpr+isCon' f = entryClosureType f .===. toJExpr Con++conTag :: JExpr -> JExpr+conTag = conTag' . closureEntry++conTag' :: JExpr -> JExpr+conTag' f = f .^ entryConTag_++-- | Get closure entry function+closureEntry :: JExpr -> JExpr+closureEntry p = p .^ closureEntry_++-- | Get closure metadata+closureMeta :: JExpr -> JExpr+closureMeta p = p .^ closureMeta_++-- | Get closure cost-center+closureCC :: JExpr -> JExpr+closureCC p = p .^ closureCC_++-- | Get closure extra field 1+closureField1 :: JExpr -> JExpr+closureField1 p = p .^ closureField1_++-- | Get closure extra field 2+closureField2 :: JExpr -> JExpr+closureField2 p = p .^ closureField2_++-- number of  arguments (arity & 0xff = arguments, arity >> 8 = number of registers)+funArity :: JExpr -> JExpr+funArity = funArity' . closureEntry++-- function arity with raw reference to the entry+funArity' :: JExpr -> JExpr+funArity' f = f .^ entryFunArity_++-- arity of a partial application+papArity :: JExpr -> JExpr+papArity cp = closureField1 (closureField2 cp)++funOrPapArity+  :: JExpr       -- ^ heap object+  -> Maybe JExpr -- ^ reference to entry, if you have one already (saves a c.f lookup twice)+  -> JExpr       -- ^ arity tag (tag >> 8 = registers, tag & 0xff = arguments)+funOrPapArity c = \case+  Nothing -> ((IfExpr (toJExpr (isFun c))) (toJExpr (funArity c)))+             (toJExpr (papArity c))+  Just f  -> ((IfExpr (toJExpr (isFun' f))) (toJExpr (funArity' f)))+             (toJExpr (papArity c))
+ compiler/GHC/StgToJS/Ids.hs view
@@ -0,0 +1,238 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Ids+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+--  Module to deal with JS identifiers+-----------------------------------------------------------------------------++module GHC.StgToJS.Ids+  ( freshUnique+  , freshIdent+  , makeIdentForId+  , cachedIdentForId+  -- * Helpers for Idents+  , identForId+  , identForIdN+  , identsForId+  , identForEntryId+  , identForDataConEntryId+  , identForDataConWorker+  -- * Helpers for variables+  , varForId+  , varForIdN+  , varsForId+  , varForEntryId+  , varForDataConEntryId+  , varForDataConWorker+  , declVarsForId+  )+where++import GHC.Prelude++import GHC.StgToJS.Types+import GHC.StgToJS.Monad+import GHC.StgToJS.CoreUtils+import GHC.StgToJS.Symbols++import GHC.JS.Syntax+import GHC.JS.Make++import GHC.Core.DataCon+import GHC.Types.Id+import GHC.Types.Unique+import GHC.Types.Unique.FM+import GHC.Types.Name+import GHC.Unit.Module+import GHC.Data.FastString+import GHC.Data.FastMutInt++import Control.Monad+import Control.Monad.IO.Class+import qualified Control.Monad.Trans.State.Strict as State+import qualified Data.Map  as M+import Data.Maybe+import qualified Data.ByteString.Char8 as BSC++-- | Get fresh unique number+freshUnique :: G Int+freshUnique = do+  id_gen <- State.gets gsId+  liftIO $ do+    -- no need for atomicFetchAdd as we don't use threads in G+    v <- readFastMutInt id_gen+    writeFastMutInt id_gen (v+1)+    pure v++-- | Get fresh local Ident of the form: h$$unit:module_uniq+freshIdent :: G Ident+freshIdent = do+  i <- freshUnique+  mod <- State.gets gsModule+  let !name = mkFreshJsSymbol mod i+  return (TxtI name)+++-- | Generate unique Ident for the given ID (uncached!)+--+-- The ident has the following forms:+--+--    global Id: h$unit:module.name[_num][_type_suffix]+--    local Id: h$$unit:module.name[_num][_type_suffix]_uniq+--+-- Note that the string is z-encoded except for "_" delimiters.+--+-- Optional "_type_suffix" can be:+--  - "_e" for IdEntry+--  - "_con_e" for IdConEntry+--+-- Optional "_num" is passed as an argument to this function. It is used for+-- Haskell Ids that require several JS variables: e.g. 64-bit numbers (Word64#,+-- Int64#), Addr#, StablePtr#, unboxed tuples, etc.+--+makeIdentForId :: Id -> Maybe Int -> IdType -> Module -> Ident+makeIdentForId i num id_type current_module = TxtI ident+  where+    exported = isExportedId i+    name     = getName i+    mod+      | exported+      , Just m <- nameModule_maybe name+      = m+      | otherwise+      = current_module++    !ident   = mkFastStringByteString $ mconcat+      [ mkJsSymbolBS exported mod (occNameFS (nameOccName name))++        -------------+        -- suffixes++        -- suffix for Ids represented with more than one JS var ("_0", "_1", etc.)+      , case num of+          Nothing -> mempty+          Just v  -> mconcat [BSC.pack "_", intBS v]++        -- suffix for entry and constructor entry+      , case id_type of+          IdPlain    -> mempty+          IdEntry    -> BSC.pack "_e"+          IdConEntry -> BSC.pack "_con_e"++        -- unique suffix for non-exported Ids+      , if exported+          then mempty+          else let (c,u) = unpkUnique (getUnique i)+               in mconcat [BSC.pack ['_',c,'_'], intBS u]+      ]++-- | Retrieve the cached Ident for the given Id if there is one. Otherwise make+-- a new one with 'makeIdentForId' and cache it.+cachedIdentForId :: Id -> Maybe Int -> IdType -> G Ident+cachedIdentForId i mi id_type = do++  -- compute key+  let !key = IdKey (getKey . getUnique $ i) (fromMaybe 0 mi) id_type++  -- lookup Ident in the Ident cache+  IdCache cache <- State.gets gsIdents+  ident <- case M.lookup key cache of+    Just ident -> pure ident+    Nothing -> do+      mod <- State.gets gsModule+      let !ident  = makeIdentForId i mi id_type mod+      let !cache' = IdCache (M.insert key ident cache)+      State.modify (\s -> s { gsIdents = cache' })+      pure ident++  -- Now update the GlobalId cache, if required++  let update_global_cache = isGlobalId i && isNothing mi && id_type == IdPlain+      -- fixme also allow caching entries for lifting?++  when (update_global_cache) $ do+    GlobalIdCache gidc <- getGlobalIdCache+    case elemUFM ident gidc of+      False -> setGlobalIdCache $ GlobalIdCache (addToUFM gidc ident (key, i))+      True  -> pure ()++  pure ident++-- | Retrieve default Ident for the given Id+identForId :: Id -> G Ident+identForId i = cachedIdentForId i Nothing IdPlain++-- | Retrieve default Ident for the given Id with sub index+--+-- Some types, Word64, Addr#, unboxed tuple have more than one corresponding JS+-- var, hence we use the sub index to identify each subpart / JS variable.+identForIdN :: Id -> Int -> G Ident+identForIdN i n = cachedIdentForId i (Just n) IdPlain++-- | Retrieve all the idents for the given Id.+identsForId :: Id -> G [Ident]+identsForId i = case typeSize (idType i) of+  0 -> pure mempty+  1 -> (:[]) <$> identForId i+  s -> mapM (identForIdN i) [1..s]+++-- | Retrieve entry Ident for the given Id+identForEntryId :: Id -> G Ident+identForEntryId i = cachedIdentForId i Nothing IdEntry++-- | Retrieve datacon entry Ident for the given Id+--+-- Different name than the datacon wrapper.+identForDataConEntryId :: Id -> G Ident+identForDataConEntryId i = cachedIdentForId i Nothing IdConEntry+++-- | Retrieve default variable name for the given Id+varForId :: Id -> G JExpr+varForId i = toJExpr <$> identForId i++-- | Retrieve default variable name for the given Id with sub index+varForIdN :: Id -> Int -> G JExpr+varForIdN i n = toJExpr <$> identForIdN i n++-- | Retrieve all the JS vars for the given Id+varsForId :: Id -> G [JExpr]+varsForId i = case typeSize (idType i) of+  0 -> pure mempty+  1 -> (:[]) <$> varForId i+  s -> mapM (varForIdN i) [1..s]+++-- | Retrieve entry variable name for the given Id+varForEntryId :: Id -> G JExpr+varForEntryId i = toJExpr <$> identForEntryId i++-- | Retrieve datacon entry variable name for the given Id+varForDataConEntryId :: Id -> G JExpr+varForDataConEntryId i = ValExpr . JVar <$> identForDataConEntryId i+++-- | Retrieve datacon worker entry variable name for the given datacon+identForDataConWorker :: DataCon -> G Ident+identForDataConWorker d = identForDataConEntryId (dataConWorkId d)++-- | Retrieve datacon worker entry variable name for the given datacon+varForDataConWorker :: DataCon -> G JExpr+varForDataConWorker d = varForDataConEntryId (dataConWorkId d)++-- | Declare all js vars for the id+declVarsForId :: Id -> G JStat+declVarsForId  i = case typeSize (idType i) of+  0 -> return mempty+  1 -> decl <$> identForId i+  s -> mconcat <$> mapM (\n -> decl <$> identForIdN i n) [1..s]+
+ compiler/GHC/StgToJS/Linker/Linker.hs view
@@ -0,0 +1,953 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections     #-}+{-# LANGUAGE LambdaCase        #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Linker.Linker+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+-- GHCJS linker, collects dependencies from the object files+-- which contain linkable units with dependency information+--+-----------------------------------------------------------------------------++module GHC.StgToJS.Linker.Linker+  ( jsLinkBinary+  , embedJsFile+  )+where++import Prelude++import GHC.Platform.Host (hostPlatformArchOS)++import GHC.JS.Make+import GHC.JS.Syntax++import GHC.Driver.Session (DynFlags(..))+import Language.Haskell.Syntax.Module.Name+import GHC.SysTools.Cpp+import GHC.SysTools++import GHC.Linker.Static.Utils (exeFileName)++import GHC.StgToJS.Linker.Types+import GHC.StgToJS.Linker.Utils+import GHC.StgToJS.Rts.Rts+import GHC.StgToJS.Object+import GHC.StgToJS.Types hiding (LinkableUnit)+import GHC.StgToJS.Symbols+import GHC.StgToJS.Printer+import GHC.StgToJS.Arg+import GHC.StgToJS.Closure++import GHC.Unit.State+import GHC.Unit.Env+import GHC.Unit.Home+import GHC.Unit.Types+import GHC.Unit.Module (moduleStableString)++import GHC.Utils.Outputable hiding ((<>))+import GHC.Utils.Panic+import GHC.Utils.Error+import GHC.Utils.Logger (Logger, logVerbAtLeast)+import GHC.Utils.Binary+import qualified GHC.Utils.Ppr as Ppr+import GHC.Utils.Monad+import GHC.Utils.TmpFs++import GHC.Types.Unique.Set++import qualified GHC.SysTools.Ar          as Ar++import qualified GHC.Data.ShortText as ST+import GHC.Data.FastString++import Control.Concurrent.MVar+import Control.Monad++import Data.Array+import qualified Data.ByteString          as B+import qualified Data.ByteString.Char8    as BC+import qualified Data.ByteString.Lazy.Char8 as BLC+import qualified Data.ByteString.Lazy     as BL+import qualified Data.ByteString          as BS+import Data.Function            (on)+import Data.IntSet              (IntSet)+import qualified Data.IntSet              as IS+import Data.IORef+import Data.List  ( partition, nub, intercalate, group, sort+                  , groupBy, intersperse,+                  )+import Data.Map.Strict          (Map)+import qualified Data.Map.Strict          as M+import Data.Maybe+import Data.Set                 (Set)+import qualified Data.Set                 as S+import Data.Word++import System.IO+import System.FilePath ((<.>), (</>), dropExtension, takeDirectory)+import System.Directory ( createDirectoryIfMissing+                        , doesFileExist+                        , getCurrentDirectory+                        , Permissions(..)+                        , setPermissions+                        , getPermissions+                        )++data LinkerStats = LinkerStats+  { bytesPerModule     :: !(Map Module Word64) -- ^ number of bytes linked per module+  , packedMetaDataSize :: !Word64              -- ^ number of bytes for metadata+  }++newtype ArchiveState = ArchiveState { loadedArchives :: IORef (Map FilePath Ar.Archive) }++emptyArchiveState :: IO ArchiveState+emptyArchiveState = ArchiveState <$> newIORef M.empty++jsLinkBinary+  :: JSLinkConfig+  -> StgToJSConfig+  -> [FilePath]+  -> Logger+  -> DynFlags+  -> UnitEnv+  -> [FilePath]+  -> [UnitId]+  -> IO ()+jsLinkBinary lc_cfg cfg js_srcs logger dflags u_env objs dep_pkgs+  | lcNoJSExecutables lc_cfg = return ()+  | otherwise = do+    -- additional objects to link are passed as FileOption ldInputs...+    let cmdline_objs = [ f | FileOption _ f <- ldInputs dflags ]+    -- discriminate JavaScript sources from real object files.+    (cmdline_js_srcs, cmdline_js_objs) <- partitionM isJsFile cmdline_objs+    let+        objs'    = map ObjFile (objs ++ cmdline_js_objs)+        js_srcs' = js_srcs ++ cmdline_js_srcs+        isRoot _ = True+        exe      = jsExeFileName dflags++    void $ link lc_cfg cfg logger u_env exe mempty dep_pkgs objs' js_srcs' isRoot mempty++-- | link and write result to disk (jsexe directory)+link :: JSLinkConfig+     -> StgToJSConfig+     -> Logger+     -> UnitEnv+     -> FilePath               -- ^ output file/directory+     -> [FilePath]             -- ^ include path for home package+     -> [UnitId]               -- ^ packages to link+     -> [LinkedObj]            -- ^ the object files we're linking+     -> [FilePath]             -- ^ extra js files to include+     -> (ExportedFun -> Bool)  -- ^ functions from the objects to use as roots (include all their deps)+     -> Set ExportedFun        -- ^ extra symbols to link in+     -> IO ()+link lc_cfg cfg logger unit_env out _include units objFiles jsFiles isRootFun extraStaticDeps = do++      -- create output directory+      createDirectoryIfMissing False out++      -------------------------------------------------------------+      -- link all Haskell code (program + dependencies) into out.js++      -- compute dependencies+      (dep_map, dep_units, all_deps, _rts_wired_functions, dep_archives)+        <- computeLinkDependencies cfg logger out unit_env units objFiles extraStaticDeps isRootFun++      -- retrieve code for dependencies+      mods <- collectDeps dep_map dep_units all_deps++      -- LTO + rendering of JS code+      link_stats <- withBinaryFile (out </> "out.js") WriteMode $ \h ->+        renderLinker h mods jsFiles++      -------------------------------------------------------------++      -- dump foreign references file (.frefs)+      unless (lcOnlyOut lc_cfg) $ do+        let frefsFile  = "out.frefs"+            -- frefs      = concatMap mc_frefs mods+            jsonFrefs  = mempty -- FIXME: toJson frefs++        BL.writeFile (out </> frefsFile <.> "json") jsonFrefs+        BL.writeFile (out </> frefsFile <.> "js")+                     ("h$checkForeignRefs(" <> jsonFrefs <> ");")++      -- dump stats+      unless (lcNoStats lc_cfg) $ do+        let statsFile = "out.stats"+        writeFile (out </> statsFile) (renderLinkerStats link_stats)++      -- link generated RTS parts into rts.js+      unless (lcNoRts lc_cfg) $ do+        BL.writeFile (out </> "rts.js") ( BLC.pack rtsDeclsText+                                         <> BLC.pack (rtsText cfg))++      -- link dependencies' JS files into lib.js+      withBinaryFile (out </> "lib.js") WriteMode $ \h -> do+        forM_ dep_archives $ \archive_file -> do+          Ar.Archive entries <- Ar.loadAr archive_file+          forM_ entries $ \entry -> do+            case getJsArchiveEntry entry of+              Nothing -> return ()+              Just bs -> do+                B.hPut   h bs+                hPutChar h '\n'++      -- link everything together into all.js+      when (generateAllJs lc_cfg) $ do+        _ <- combineFiles lc_cfg out+        writeHtml    out+        writeRunMain out+        writeRunner lc_cfg out+        writeExterns out+++computeLinkDependencies+  :: StgToJSConfig+  -> Logger+  -> String+  -> UnitEnv+  -> [UnitId]+  -> [LinkedObj]+  -> Set ExportedFun+  -> (ExportedFun -> Bool)+  -> IO (Map Module (Deps, DepsLocation), [UnitId], Set LinkableUnit, Set ExportedFun, [FilePath])+computeLinkDependencies cfg logger target unit_env units objFiles extraStaticDeps isRootFun = do++  (objDepsMap, objRequiredUnits) <- loadObjDeps objFiles++  let roots    = S.fromList . filter isRootFun $ concatMap (M.keys . depsHaskellExported . fst) (M.elems objDepsMap)+      rootMods = map (moduleNameString . moduleName . head) . group . sort . map funModule . S.toList $ roots+      objPkgs  = map moduleUnitId $ nub (M.keys objDepsMap)++  when (logVerbAtLeast logger 2) $ void $ do+    compilationProgressMsg logger $ hcat+      [ text "Linking ", text target, text " (", text (intercalate "," rootMods), char ')' ]+    compilationProgressMsg logger $ hcat+      [ text "objDepsMap ", ppr objDepsMap ]+    compilationProgressMsg logger $ hcat+      [ text "objFiles ", ppr objFiles ]++  let (rts_wired_units, rts_wired_functions) = rtsDeps units++  -- all the units we want to link together, without their dependencies+  let root_units = filter (/= mainUnitId)+                   $ nub+                   $ rts_wired_units ++ reverse objPkgs ++ reverse units++  -- all the units we want to link together, including their dependencies,+  -- preload units, and backpack instantiations+  all_units_infos <- mayThrowUnitErr (preloadUnitsInfo' unit_env root_units)++  let all_units = fmap unitId all_units_infos++  dep_archives <- getPackageArchives cfg unit_env all_units+  env <- newGhcjsEnv+  (archsDepsMap, archsRequiredUnits) <- loadArchiveDeps env dep_archives++  when (logVerbAtLeast logger 2) $+    logInfo logger $ hang (text "Linking with archives:") 2 (vcat (fmap text dep_archives))++  -- compute dependencies+  let dep_units      = all_units ++ [homeUnitId (ue_unsafeHomeUnit $ unit_env)]+      dep_map        = objDepsMap `M.union` archsDepsMap+      excluded_units = S.empty+      dep_fun_roots  = roots `S.union` rts_wired_functions `S.union` extraStaticDeps+      dep_unit_roots = archsRequiredUnits ++ objRequiredUnits++  all_deps <- getDeps (fmap fst dep_map) excluded_units dep_fun_roots dep_unit_roots++  when (logVerbAtLeast logger 2) $+    logInfo logger $ hang (text "Units to link:") 2 (vcat (fmap ppr dep_units))+    -- logInfo logger $ hang (text "All deps:") 2 (vcat (fmap ppr (S.toList all_deps)))++  return (dep_map, dep_units, all_deps, rts_wired_functions, dep_archives)+++-- | Compiled module+data ModuleCode = ModuleCode+  { mc_module   :: !Module+  , mc_js_code  :: !JStat+  , mc_exports  :: !B.ByteString        -- ^ rendered exports+  , mc_closures :: ![ClosureInfo]+  , mc_statics  :: ![StaticInfo]+  , mc_frefs    :: ![ForeignJSRef]+  }++-- | ModuleCode after link with other modules.+--+-- It contains less information than ModuleCode because they have been commoned+-- up into global "metadata" for the whole link.+data CompactedModuleCode = CompactedModuleCode+  { cmc_module  :: !Module+  , cmc_js_code :: !JStat+  , cmc_exports :: !B.ByteString        -- ^ rendered exports+  }++-- | Link modules and pretty-print them into the given Handle+renderLinker+  :: Handle+  -> [ModuleCode] -- ^ linked code per module+  -> [FilePath]   -- ^ additional JS files+  -> IO LinkerStats+renderLinker h mods jsFiles = do++  -- link modules+  let (compacted_mods, meta) = linkModules mods++  let+    putBS   = B.hPut h+    putJS x = do+      before <- hTell h+      Ppr.printLeftRender h (pretty x)+      hPutChar h '\n'+      after <- hTell h+      pure $! (after - before)++  ---------------------------------------------------------+  -- Pretty-print JavaScript code for all the dependencies.+  --+  -- We have to pretty-print at link time because we want to be able to perform+  -- global link-time optimisations (e.g. renamings) on the whole generated JS+  -- file.++  -- modules themselves+  mod_sizes <- forM compacted_mods $ \m -> do+    !mod_size <- fromIntegral <$> putJS (cmc_js_code m)+    let !mod_mod  = cmc_module m+    pure (mod_mod, mod_size)++  -- commoned up metadata+  !meta_length <- fromIntegral <$> putJS meta++  -- module exports+  mapM_ (putBS . cmc_exports) compacted_mods++  -- explicit additional JS files+  mapM_ (\i -> B.readFile i >>= putBS) jsFiles++  -- stats+  let link_stats = LinkerStats+        { bytesPerModule     = M.fromList mod_sizes+        , packedMetaDataSize = meta_length+        }++  pure link_stats++-- | Render linker stats+renderLinkerStats :: LinkerStats -> String+renderLinkerStats s =+  intercalate "\n\n" [meta_stats, package_stats, module_stats] <> "\n\n"+  where+    meta = packedMetaDataSize s+    meta_stats = "number of modules: " <> show (length bytes_per_mod)+                 <> "\npacked metadata:   " <> show meta++    bytes_per_mod = M.toList $ bytesPerModule s++    show_unit (UnitId fs) = unpackFS fs++    ps :: Map UnitId Word64+    ps = M.fromListWith (+) . map (\(m,s) -> (moduleUnitId m,s)) $ bytes_per_mod++    pad :: Int -> String -> String+    pad n t = let l = length t+              in  if l < n then t <> replicate (n-l) ' ' else t++    pkgMods :: [[(Module,Word64)]]+    pkgMods = groupBy ((==) `on` (moduleUnitId . fst)) bytes_per_mod++    showMod :: (Module, Word64) -> String+    showMod (m,s) = pad 40 ("    " <> moduleStableString m <> ":") <> show s <> "\n"++    package_stats :: String+    package_stats = "code size summary per package (in bytes):\n\n"+                     <> concatMap (\(p,s) -> pad 25 (show_unit p <> ":") <> show s <> "\n") (M.toList ps)++    module_stats :: String+    module_stats = "code size per module (in bytes):\n\n" <> unlines (map (concatMap showMod) pkgMods)+++getPackageArchives :: StgToJSConfig -> UnitEnv -> [UnitId] -> IO [FilePath]+getPackageArchives cfg unit_env units =+  filterM doesFileExist [ ST.unpack p </> "lib" ++ ST.unpack l ++ profSuff <.> "a"+                        | u <- units+                        , p <- getInstalledPackageLibDirs ue_state u+                        , l <- getInstalledPackageHsLibs  ue_state u+                        ]+  where+    ue_state = ue_units unit_env++    -- XXX the profiling library name is probably wrong now+    profSuff | csProf cfg = "_p"+             | otherwise  = ""+++-- | Combine rts.js, lib.js, out.js to all.js that can be run+-- directly with node.js or SpiderMonkey jsshell+combineFiles :: JSLinkConfig+             -> FilePath+             -> IO ()+combineFiles cfg fp = do+  let files = map (fp </>) ["rts.js", "lib.js", "out.js"]+  withBinaryFile (fp </> "all.js") WriteMode $ \h -> do+    let cpy i = B.readFile i >>= B.hPut h+    mapM_ cpy files+    unless (lcNoHsMain cfg) $ do+      B.hPut h runMainJS++-- | write the index.html file that loads the program if it does not exit+writeHtml+  :: FilePath -- ^ output directory+  -> IO ()+writeHtml out = do+  let htmlFile = out </> "index.html"+  e <- doesFileExist htmlFile+  unless e $+    B.writeFile htmlFile templateHtml+++templateHtml :: B.ByteString+templateHtml =+  "<!DOCTYPE html>\n\+  \<html>\n\+  \  <head>\n\+  \  </head>\n\+  \  <body>\n\+  \  </body>\n\+  \  <script language=\"javascript\" src=\"all.js\" defer></script>\n\+  \</html>"++-- | write the runmain.js file that will be run with defer so that it runs after+-- index.html is loaded+writeRunMain+  :: FilePath -- ^ output directory+  -> IO ()+writeRunMain out = do+  let runMainFile = out </> "runmain.js"+  e <- doesFileExist runMainFile+  unless e $+    B.writeFile runMainFile runMainJS++runMainJS :: B.ByteString+runMainJS = "h$main(h$mainZCZCMainzimain);\n"++writeRunner :: JSLinkConfig -- ^ Settings+            -> FilePath     -- ^ Output directory+            -> IO ()+writeRunner _settings out = do+  cd    <- getCurrentDirectory+  let arch_os = hostPlatformArchOS+  let runner  = cd </> exeFileName arch_os False (Just (dropExtension out))+      srcFile = out </> "all" <.> "js"+      nodePgm :: B.ByteString+      nodePgm = "node"+  src <- B.readFile (cd </> srcFile)+  B.writeFile runner ("#!/usr/bin/env " <> nodePgm <> "\n" <> src)+  perms <- getPermissions runner+  setPermissions runner (perms {executable = True})++rtsExterns :: FastString+rtsExterns =+  "// GHCJS RTS externs for closure compiler ADVANCED_OPTIMIZATIONS\n\n" <>+  mconcat (map (\x -> "/** @type {*} */\nObject.d" <> mkFastString (show x) <> ";\n")+               [(7::Int)..16384])++writeExterns :: FilePath -> IO ()+writeExterns out = writeFile (out </> "all.js.externs")+  $ unpackFS rtsExterns++-- | get all dependencies for a given set of roots+getDeps :: Map Module Deps  -- ^ loaded deps+        -> Set LinkableUnit -- ^ don't link these blocks+        -> Set ExportedFun  -- ^ start here+        -> [LinkableUnit]   -- ^ and also link these+        -> IO (Set LinkableUnit)+getDeps loaded_deps base fun startlu = go' S.empty (S.fromList startlu) (S.toList fun)+  where+    go :: Set LinkableUnit+       -> Set LinkableUnit+       -> IO (Set LinkableUnit)+    go result open = case S.minView open of+      Nothing -> return result+      Just (lu@(lmod,n), open') ->+          case M.lookup lmod loaded_deps of+            Nothing -> pprPanic "getDeps.go: object file not loaded for:  " (pprModule lmod)+            Just (Deps _ _ _ b) ->+              let block = b!n+                  result' = S.insert lu result+              in go' result'+                 (addOpen result' open' $+                   map (lmod,) (blockBlockDeps block)) (blockFunDeps block)++    go' :: Set LinkableUnit+        -> Set LinkableUnit+        -> [ExportedFun]+        -> IO (Set LinkableUnit)+    go' result open [] = go result open+    go' result open (f:fs) =+        let key = funModule f+        in  case M.lookup key loaded_deps of+              Nothing -> pprPanic "getDeps.go': object file not loaded for:  " $ pprModule key+              Just (Deps _m _r e _b) ->+                 let lun :: Int+                     lun = fromMaybe (pprPanic "exported function not found: " $ ppr f)+                                     (M.lookup f e)+                     lu  = (key, lun)+                 in  go' result (addOpen result open [lu]) fs++    addOpen :: Set LinkableUnit -> Set LinkableUnit -> [LinkableUnit]+            -> Set LinkableUnit+    addOpen result open newUnits =+      let alreadyLinked s = S.member s result ||+                            S.member s open   ||+                            S.member s base+      in  open `S.union` S.fromList (filter (not . alreadyLinked) newUnits)++-- | collect dependencies for a set of roots+collectDeps :: Map Module (Deps, DepsLocation) -- ^ Dependency map+            -> [UnitId]                        -- ^ packages, code linked in this order+            -> Set LinkableUnit                -- ^ All dependencides+            -> IO [ModuleCode]+collectDeps mod_deps packages all_deps = do++  -- read ghc-prim first, since we depend on that for static initialization+  let packages' = uncurry (++) $ partition (== primUnitId) (nub packages)++      units_by_module :: Map Module IntSet+      units_by_module = M.fromListWith IS.union $+                      map (\(m,n) -> (m, IS.singleton n)) (S.toList all_deps)++      mod_deps_bypkg :: Map UnitId [(Deps, DepsLocation)]+      mod_deps_bypkg = M.fromListWith (++)+                        (map (\(m,v) -> (moduleUnitId m,[v])) (M.toList mod_deps))++  ar_state <- emptyArchiveState+  fmap (catMaybes . concat) . forM packages' $ \pkg ->+    mapM (uncurry $ extractDeps ar_state units_by_module)+         (fromMaybe [] $ M.lookup pkg mod_deps_bypkg)++extractDeps :: ArchiveState+            -> Map Module IntSet+            -> Deps+            -> DepsLocation+            -> IO (Maybe ModuleCode)+extractDeps ar_state units deps loc =+  case M.lookup mod units of+    Nothing       -> return Nothing+    Just mod_units -> Just <$> do+      let selector n _  = fromIntegral n `IS.member` mod_units || isGlobalUnit (fromIntegral n)+      case loc of+        ObjectFile fp -> do+          us <- readObjectUnits fp selector+          pure (collectCode us)+        ArchiveFile a -> do+          obj <- readArObject ar_state mod a+          us <- getObjectUnits obj selector+          pure (collectCode us)+        InMemory _n obj -> do+          us <- getObjectUnits obj selector+          pure (collectCode us)+  where+    mod           = depsModule deps+    newline       = BC.pack "\n"+    mk_exports    = mconcat . intersperse newline . filter (not . BS.null) . map oiRaw+    mk_js_code    = mconcat . map oiStat+    collectCode l = ModuleCode+                      { mc_module   = mod+                      , mc_js_code  = mk_js_code l+                      , mc_exports  = mk_exports l+                      , mc_closures = concatMap oiClInfo l+                      , mc_statics  = concatMap oiStatic l+                      , mc_frefs    = concatMap oiFImports l+                      }++readArObject :: ArchiveState -> Module -> FilePath -> IO Object+readArObject ar_state mod ar_file = do+  loaded_ars <- readIORef (loadedArchives ar_state)+  (Ar.Archive entries) <- case M.lookup ar_file loaded_ars of+    Just a -> pure a+    Nothing -> do+      a <- Ar.loadAr ar_file+      modifyIORef (loadedArchives ar_state) (M.insert ar_file a)+      pure a++  -- look for the right object in archive+  let go_entries = \case+        -- XXX this shouldn't be an exception probably+        [] -> panic $ "could not find object for module "+                      ++ moduleNameString (moduleName mod)+                      ++ " in "+                      ++ ar_file++        (e:es) -> do+          let bs = Ar.filedata e+          bh <- unsafeUnpackBinBuffer bs+          getObjectHeader bh >>= \case+            Left _         -> go_entries es -- not a valid object entry+            Right mod_name+              | mod_name /= moduleName mod+              -> go_entries es -- not the module we're looking for+              | otherwise+              -> getObjectBody bh mod_name -- found it++  go_entries entries+++-- | A helper function to read system dependencies that are hardcoded+diffDeps+  :: [UnitId]                    -- ^ Packages that are already Linked+  -> ([UnitId], Set ExportedFun) -- ^ New units and functions to link+  -> ([UnitId], Set ExportedFun) -- ^ Diff+diffDeps pkgs (deps_pkgs,deps_funs) =+  ( filter   linked_pkg deps_pkgs+  , S.filter linked_fun deps_funs+  )+  where+    linked_fun f = moduleUnitId (funModule f) `S.member` linked_pkgs+    linked_pkg p = S.member p linked_pkgs+    linked_pkgs  = S.fromList pkgs++-- | dependencies for the RTS, these need to be always linked+rtsDeps :: [UnitId] -> ([UnitId], Set ExportedFun)+rtsDeps pkgs = diffDeps pkgs $+  ( [baseUnitId, primUnitId]+  , S.fromList $ concat+      [ mkBaseFuns "GHC.Conc.Sync"+          ["reportError"]+      , mkBaseFuns "Control.Exception.Base"+          ["nonTermination"]+      , mkBaseFuns "GHC.Exception.Type"+          [ "SomeException"+          , "underflowException"+          , "overflowException"+          , "divZeroException"+          ]+      , mkBaseFuns "GHC.TopHandler"+          [ "runMainIO"+          , "topHandler"+          ]+      , mkBaseFuns "GHC.Base"+          ["$fMonadIO"]+      , mkBaseFuns "GHC.Maybe"+          [ "Nothing"+          , "Just"+          ]+      , mkBaseFuns "GHC.Ptr"+          ["Ptr"]+      , mkBaseFuns "GHC.JS.Prim"+          [ "JSVal"+          , "JSException"+          , "$fShowJSException"+          , "$fExceptionJSException"+          , "resolve"+          , "resolveIO"+          , "toIO"+          ]+      , mkBaseFuns "GHC.JS.Prim.Internal"+          [ "wouldBlock"+          , "blockedIndefinitelyOnMVar"+          , "blockedIndefinitelyOnSTM"+          , "ignoreException"+          , "setCurrentThreadResultException"+          , "setCurrentThreadResultValue"+          ]+      , mkPrimFuns "GHC.Types"+          [ ":"+          , "[]"+          ]+      , mkPrimFuns "GHC.Tuple.Prim"+          [ "(,)"+          , "(,,)"+          , "(,,,)"+          , "(,,,,)"+          , "(,,,,,)"+          , "(,,,,,,)"+          , "(,,,,,,,)"+          , "(,,,,,,,,)"+          , "(,,,,,,,,,)"+          ]+      ]+  )++-- | Export the functions in base+mkBaseFuns :: FastString -> [FastString] -> [ExportedFun]+mkBaseFuns = mkExportedFuns baseUnitId++-- | Export the Prim functions+mkPrimFuns :: FastString -> [FastString] -> [ExportedFun]+mkPrimFuns = mkExportedFuns primUnitId++-- | Given a @UnitId@, a module name, and a set of symbols in the module,+-- package these into an @ExportedFun@.+mkExportedFuns :: UnitId -> FastString -> [FastString] -> [ExportedFun]+mkExportedFuns uid mod_name symbols = map mk_fun symbols+  where+    mod        = mkModule (RealUnit (Definite uid)) (mkModuleNameFS mod_name)+    mk_fun sym = ExportedFun mod (LexicalFastString (mkJsSymbol True mod sym))++-- | read all dependency data from the to-be-linked files+loadObjDeps :: [LinkedObj] -- ^ object files to link+            -> IO (Map Module (Deps, DepsLocation), [LinkableUnit])+loadObjDeps objs = (prepareLoadedDeps . catMaybes) <$> mapM readDepsFromObj objs++-- | Load dependencies for the Linker from Ar+loadArchiveDeps :: GhcjsEnv+                -> [FilePath]+                -> IO ( Map Module (Deps, DepsLocation)+                      , [LinkableUnit]+                      )+loadArchiveDeps env archives = modifyMVar (linkerArchiveDeps env) $ \m ->+  case M.lookup archives' m of+    Just r  -> return (m, r)+    Nothing -> loadArchiveDeps' archives >>= \r -> return (M.insert archives' r m, r)+  where+     archives' = S.fromList archives++loadArchiveDeps' :: [FilePath]+                 -> IO ( Map Module (Deps, DepsLocation)+                       , [LinkableUnit]+                       )+loadArchiveDeps' archives = do+  archDeps <- forM archives $ \file -> do+    (Ar.Archive entries) <- Ar.loadAr file+    catMaybes <$> mapM (readEntry file) entries+  return (prepareLoadedDeps $ concat archDeps)+    where+      readEntry :: FilePath -> Ar.ArchiveEntry -> IO (Maybe (Deps, DepsLocation))+      readEntry ar_file ar_entry = do+          let bs = Ar.filedata ar_entry+          bh <- unsafeUnpackBinBuffer bs+          getObjectHeader bh >>= \case+            Left _         -> pure Nothing -- not a valid object entry+            Right mod_name -> do+              obj <- getObjectBody bh mod_name+              let !deps = objDeps obj+              pure $ Just (deps, ArchiveFile ar_file)++-- | Predicate to check that an entry in Ar is a JS source+-- and to return it without its header+getJsArchiveEntry :: Ar.ArchiveEntry -> Maybe B.ByteString+getJsArchiveEntry entry = getJsBS (Ar.filedata entry)++-- | Predicate to check that a file is a JS source+isJsFile :: FilePath -> IO Bool+isJsFile fp = withBinaryFile fp ReadMode $ \h -> do+  bs <- B.hGet h jsHeaderLength+  pure (isJsBS bs)++isJsBS :: B.ByteString -> Bool+isJsBS bs = isJust (getJsBS bs)++-- | Get JS source with its header (if it's one)+getJsBS :: B.ByteString -> Maybe B.ByteString+getJsBS bs = B.stripPrefix jsHeader bs++-- Header added to JS sources to discriminate them from other object files.+-- They all have .o extension but JS sources have this header.+jsHeader :: B.ByteString+jsHeader = "//JavaScript"++jsHeaderLength :: Int+jsHeaderLength = B.length jsHeader++++prepareLoadedDeps :: [(Deps, DepsLocation)]+                  -> ( Map Module (Deps, DepsLocation)+                     , [LinkableUnit]+                     )+prepareLoadedDeps deps =+  let req     = concatMap (requiredUnits . fst) deps+      depsMap = M.fromList $ map (\d -> (depsModule (fst d), d)) deps+  in  (depsMap, req)++requiredUnits :: Deps -> [LinkableUnit]+requiredUnits d = map (depsModule d,) (IS.toList $ depsRequired d)++-- | read dependencies from an object that might have already been into memory+-- pulls in all Deps from an archive+readDepsFromObj :: LinkedObj -> IO (Maybe (Deps, DepsLocation))+readDepsFromObj = \case+  ObjLoaded name obj -> do+    let !deps = objDeps obj+    pure $ Just (deps,InMemory name obj)+  ObjFile file -> do+    readObjectDeps file >>= \case+      Nothing   -> pure Nothing+      Just deps -> pure $ Just (deps,ObjectFile file)+++-- | Embed a JS file into a .o file+--+-- The JS file is merely copied into a .o file with an additional header+-- ("//Javascript") in order to be recognized later on.+--+-- JS files may contain option pragmas of the form: //#OPTIONS:+-- For now, only the CPP option is supported. If the CPP option is set, we+-- append some common CPP definitions to the file and call cpp on it.+embedJsFile :: Logger -> DynFlags -> TmpFs -> UnitEnv -> FilePath -> FilePath -> IO ()+embedJsFile logger dflags tmpfs unit_env input_fn output_fn = do+  let profiling  = False -- FIXME: add support for profiling way++  createDirectoryIfMissing True (takeDirectory output_fn)++  -- the header lets the linker recognize processed JavaScript files+  -- But don't add JavaScript header to object files!++  is_js_obj <- if True+                then pure False+                else isJsObjectFile input_fn+                -- FIXME (Sylvain 2022-09): this call makes the+                -- testsuite go into a loop, I don't know why yet!+                -- Disabling it for now.++  if is_js_obj+    then copyWithHeader "" input_fn output_fn+    else do+      -- header appended to JS files stored as .o to recognize them.+      let header = "//JavaScript\n"+      jsFileNeedsCpp input_fn >>= \case+        False -> copyWithHeader header input_fn output_fn+        True  -> do++          -- append common CPP definitions to the .js file.+          -- They define macros that avoid directly wiring zencoded names+          -- in RTS JS files+          pp_fn <- newTempName logger tmpfs (tmpDir dflags) TFL_CurrentModule "js"+          payload <- B.readFile input_fn+          B.writeFile pp_fn (commonCppDefs profiling <> payload)++          -- run CPP on the input JS file+          js_fn <- newTempName logger tmpfs (tmpDir dflags) TFL_CurrentModule "js"+          let+            cpp_opts = CppOpts+              { cppUseCc       = True+              , cppLinePragmas = False -- LINE pragmas aren't JS compatible+              }+          doCpp logger+                  tmpfs+                  dflags+                  unit_env+                  cpp_opts+                  pp_fn+                  js_fn+          -- add header to recognize the object as a JS file+          copyWithHeader header js_fn output_fn++jsFileNeedsCpp :: FilePath -> IO Bool+jsFileNeedsCpp fn = do+  opts <- getOptionsFromJsFile fn+  pure (CPP `elem` opts)++-- | Link module codes.+--+-- Performs link time optimizations and produces one JStat per module plus some+-- commoned up initialization code.+linkModules :: [ModuleCode] -> ([CompactedModuleCode], JStat)+linkModules mods = (compact_mods, meta)+  where+    compact_mods = map compact mods++    -- here GHCJS used to:+    --  - deduplicate declarations+    --  - rename local variables into shorter ones+    --  - compress initialization data+    -- but we haven't ported it (yet).+    compact m = CompactedModuleCode+      { cmc_js_code = mc_js_code m+      , cmc_module  = mc_module m+      , cmc_exports = mc_exports m+      }++    -- common up statics: different bindings may reference the same statics, we+    -- filter them here to initialize them once+    statics = nubStaticInfo (concatMap mc_statics mods)++    infos   = concatMap mc_closures mods+    meta = mconcat+            -- render metadata as individual statements+            [ mconcat (map staticDeclStat statics)+            , mconcat (map staticInitStat statics)+            , mconcat (map (closureInfoStat True) infos)+            ]++-- | Only keep a single StaticInfo with a given name+nubStaticInfo :: [StaticInfo] -> [StaticInfo]+nubStaticInfo = go emptyUniqSet+  where+    go us = \case+      []     -> []+      (x:xs) ->+        -- only match on siVar. There is no reason for the initializing value to+        -- be different for the same global name.+        let name = siVar x+        in if elementOfUniqSet name us+          then go us xs+          else x : go (addOneToUniqSet us name) xs++-- | Initialize a global object.+--+-- All global objects have to be declared (staticInfoDecl) first.+staticInitStat :: StaticInfo -> JStat+staticInitStat (StaticInfo i sv mcc) =+  case sv of+    StaticData con args         -> appS "h$sti" $ add_cc_arg+                                    [ var i+                                    , var con+                                    , jsStaticArgs args+                                    ]+    StaticFun  f   args         -> appS "h$sti" $ add_cc_arg+                                    [ var i+                                    , var f+                                    , jsStaticArgs args+                                    ]+    StaticList args mt          -> appS "h$stl" $ add_cc_arg+                                    [ var i+                                    , jsStaticArgs args+                                    , toJExpr $ maybe null_ (toJExpr . TxtI) mt+                                    ]+    StaticThunk (Just (f,args)) -> appS "h$stc" $ add_cc_arg+                                    [ var i+                                    , var f+                                    , jsStaticArgs args+                                    ]+    _                           -> mempty+  where+    -- add optional cost-center argument+    add_cc_arg as = case mcc of+      Nothing -> as+      Just cc -> as ++ [toJExpr cc]++-- | declare and do first-pass init of a global object (create JS object for heap objects)+staticDeclStat :: StaticInfo -> JStat+staticDeclStat (StaticInfo global_name static_value _) = decl+  where+    global_ident = TxtI global_name+    decl_init v  = global_ident ||= v+    decl_no_init = appS "h$di" [toJExpr global_ident]++    decl = case static_value of+      StaticUnboxed u     -> decl_init (unboxed_expr u)+      StaticThunk Nothing -> decl_no_init -- CAF initialized in an alternative way+      _                   -> decl_init (app "h$d" [])++    unboxed_expr = \case+      StaticUnboxedBool b          -> app "h$p" [toJExpr b]+      StaticUnboxedInt i           -> app "h$p" [toJExpr i]+      StaticUnboxedDouble d        -> app "h$p" [toJExpr (unSaneDouble d)]+      StaticUnboxedString str      -> app "h$rawStringData" [ValExpr (to_byte_list str)]+      StaticUnboxedStringOffset {} -> 0++    to_byte_list = JList . map (Int . fromIntegral) . BS.unpack
+ compiler/GHC/StgToJS/Linker/Types.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PartialTypeSignatures #-}+{-# LANGUAGE LambdaCase #-}++{-# OPTIONS_GHC -Wno-orphans #-} -- for Ident's Binary instance++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Linker.Types+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+-----------------------------------------------------------------------------++module GHC.StgToJS.Linker.Types+  ( GhcjsEnv (..)+  , newGhcjsEnv+  , JSLinkConfig (..)+  , defaultJSLinkConfig+  , generateAllJs+  , LinkedObj (..)+  , LinkableUnit+  )+where++import GHC.StgToJS.Object++import GHC.Unit.Types+import GHC.Utils.Outputable (hsep,Outputable(..),text,ppr)++import Data.Map.Strict      (Map)+import qualified Data.Map.Strict as M+import Data.Set             (Set)++import Control.Concurrent.MVar++import System.IO++import Prelude++--------------------------------------------------------------------------------+-- Linker Config+--------------------------------------------------------------------------------++data JSLinkConfig = JSLinkConfig+  { lcNoJSExecutables    :: Bool+  , lcNoHsMain           :: Bool+  , lcOnlyOut            :: Bool+  , lcNoRts              :: Bool+  , lcNoStats            :: Bool+  }++-- | we generate a runnable all.js only if we link a complete application,+--   no incremental linking and no skipped parts+generateAllJs :: JSLinkConfig -> Bool+generateAllJs s = not (lcOnlyOut s) && not (lcNoRts s)++defaultJSLinkConfig :: JSLinkConfig+defaultJSLinkConfig = JSLinkConfig+  { lcNoJSExecutables = False+  , lcNoHsMain        = False+  , lcOnlyOut         = False+  , lcNoRts           = False+  , lcNoStats         = False+  }++--------------------------------------------------------------------------------+-- Linker Environment+--------------------------------------------------------------------------------++-- | A @LinkableUnit@ is a pair of a module and the index of the block in the+-- object file+type LinkableUnit = (Module, Int)++-- | An object file that's either already in memory (with name) or on disk+data LinkedObj+  = ObjFile   FilePath      -- ^ load from this file+  | ObjLoaded String Object -- ^ already loaded: description and payload++instance Outputable LinkedObj where+  ppr = \case+    ObjFile fp    -> hsep [text "ObjFile", text fp]+    ObjLoaded s o -> hsep [text "ObjLoaded", text s, ppr (objModuleName o)]++data GhcjsEnv = GhcjsEnv+  { linkerArchiveDeps :: MVar (Map (Set FilePath)+                                   (Map Module (Deps, DepsLocation)+                                   , [LinkableUnit]+                                   )+                              )+  }++-- | return a fresh @GhcjsEnv@+newGhcjsEnv :: IO GhcjsEnv+newGhcjsEnv = GhcjsEnv <$> newMVar M.empty
+ compiler/GHC/StgToJS/Linker/Utils.hs view
@@ -0,0 +1,308 @@+{-# LANGUAGE OverloadedStrings  #-}+{-# LANGUAGE MultiWayIf  #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Linker.Utils+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+-- Various utilies used in the JS Linker+--+-----------------------------------------------------------------------------++module GHC.StgToJS.Linker.Utils+  ( getOptionsFromJsFile+  , JSOption(..)+  , jsExeFileName+  , getInstalledPackageLibDirs+  , getInstalledPackageHsLibs+  , commonCppDefs+  )+where++import           System.FilePath+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as Char8+import           Data.ByteString (ByteString)++import          GHC.Driver.Session++import          GHC.Data.ShortText+import          GHC.Unit.State+import          GHC.Unit.Types++import          GHC.StgToJS.Types++import           Prelude+import GHC.Platform+import Data.List (isPrefixOf)+import System.IO+import Data.Char (isSpace)+import qualified Control.Exception as Exception++-- | Retrieve library directories provided by the @UnitId@ in @UnitState@+getInstalledPackageLibDirs :: UnitState -> UnitId -> [ShortText]+getInstalledPackageLibDirs us = maybe mempty unitLibraryDirs . lookupUnitId us++-- | Retrieve the names of the libraries provided by @UnitId@+getInstalledPackageHsLibs :: UnitState -> UnitId -> [ShortText]+getInstalledPackageHsLibs us = maybe mempty unitLibraries . lookupUnitId us++-- | A constant holding the JavaScript executable Filename extension+jsexeExtension :: String+jsexeExtension = "jsexe"++-- | CPP definitions that are inserted into every .pp file+commonCppDefs :: Bool -> ByteString+commonCppDefs profiling = case profiling of+  True  -> commonCppDefs_profiled+  False -> commonCppDefs_vanilla++-- | CPP definitions for normal operation and profiling. Use CAFs for+-- commonCppDefs_* so that they are shared for every CPP file+commonCppDefs_vanilla, commonCppDefs_profiled :: ByteString+commonCppDefs_vanilla  = genCommonCppDefs False+commonCppDefs_profiled = genCommonCppDefs True++-- | Generate CPP Definitions depending on a profiled or normal build. This+-- occurs at link time.+genCommonCppDefs :: Bool -> ByteString+genCommonCppDefs profiling = mconcat+  [+  -- constants+    let mk_int_def n v   = "#define " <> Char8.pack n <> " (" <> Char8.pack (show v) <> ")\n"+        -- generate "#define CLOSURE_TYPE_xyz (num)" defines+        mk_closure_def t = mk_int_def (ctJsName t) (ctNum t)+        closure_defs     = map mk_closure_def [minBound..maxBound]+        -- generate "#define THREAD_xyz_xyz (num)" defines+        mk_thread_def t  = mk_int_def (threadStatusJsName t) (threadStatusNum t)+        thread_defs      = map mk_thread_def [minBound..maxBound]+    in mconcat (closure_defs ++ thread_defs)++  -- low-level heap object manipulation macros+  , if profiling+      then mconcat+        [ "#define MK_TUP2(x1,x2)                           (h$c2(h$ghczmprimZCGHCziTupleziPrimziZLz2cUZR_con_e,(x1),(x2),h$currentThread?h$currentThread.ccs:h$CCS_SYSTEM))\n"+        , "#define MK_TUP3(x1,x2,x3)                        (h$c3(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUZR_con_e,(x1),(x2),(x3),h$currentThread?h$currentThread.ccs:h$CCS_SYSTEM))\n"+        , "#define MK_TUP4(x1,x2,x3,x4)                     (h$c4(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),h$currentThread?h$currentThread.ccs:h$CCS_SYSTEM))\n"+        , "#define MK_TUP5(x1,x2,x3,x4,x5)                  (h$c5(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),(x5),h$currentThread?h$currentThread.ccs:h$CCS_SYSTEM))\n"+        , "#define MK_TUP6(x1,x2,x3,x4,x5,x6)               (h$c6(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),(x5),(x6),h$currentThread?h$currentThread.ccs:h$CCS_SYSTEM))\n"+        , "#define MK_TUP7(x1,x2,x3,x4,x5,x6,x7)            (h$c7(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),(x5),(x6),(x7),h$currentThread?h$currentThread.ccs:h$CCS_SYSTEM))\n"+        , "#define MK_TUP8(x1,x2,x3,x4,x5,x6,x7,x8)         (h$c8(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUz2cUz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),(x5),(x6),(x7),(x8),h$currentThread?h$currentThread.ccs:h$CCS_SYSTEM))\n"+        , "#define MK_TUP9(x1,x2,x3,x4,x5,x6,x7,x8,x9)      (h$c9(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUz2cUz2cUz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),(x5),(x6),(x7),(x8),(x9),h$currentThread?h$currentThread.ccs:h$CCS_SYSTEM))\n"+        , "#define MK_TUP10(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10) (h$c10(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUz2cUz2cUz2cUz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),(x5),(x6),(x7),(x8),(x9),(x10),h$currentThread?h$currentThread.ccs:h$CCS_SYSTEM))\n"+        ]+      else mconcat+        [ "#define MK_TUP2(x1,x2)                           (h$c2(h$ghczmprimZCGHCziTupleziPrimziZLz2cUZR_con_e,(x1),(x2)))\n"+        , "#define MK_TUP3(x1,x2,x3)                        (h$c3(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUZR_con_e,(x1),(x2),(x3)))\n"+        , "#define MK_TUP4(x1,x2,x3,x4)                     (h$c4(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4)))\n"+        , "#define MK_TUP5(x1,x2,x3,x4,x5)                  (h$c5(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),(x5)))\n"+        , "#define MK_TUP6(x1,x2,x3,x4,x5,x6)               (h$c6(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),(x5),(x6)))\n"+        , "#define MK_TUP7(x1,x2,x3,x4,x5,x6,x7)            (h$c7(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),(x5),(x6),(x7)))\n"+        , "#define MK_TUP8(x1,x2,x3,x4,x5,x6,x7,x8)         (h$c8(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUz2cUz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),(x5),(x6),(x7),(x8)))\n"+        , "#define MK_TUP9(x1,x2,x3,x4,x5,x6,x7,x8,x9)      (h$c9(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUz2cUz2cUz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),(x5),(x6),(x7),(x8),(x9)))\n"+        , "#define MK_TUP10(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10) (h$c10(h$ghczmprimZCGHCziTupleziPrimziZLz2cUz2cUz2cUz2cUz2cUz2cUz2cUz2cUz2cUZR_con_e,(x1),(x2),(x3),(x4),(x5),(x6),(x7),(x8),(x9),(x10)))\n"+        ]++  , "#define TUP2_1(x) ((x).d1)\n"+  , "#define TUP2_2(x) ((x).d2)\n"++  -- GHCJS.Prim.JSVal+  , if profiling+      then "#define MK_JSVAL(x) (h$baseZCGHCziJSziPrimziJSVal_con_e, (x), h$CCS_SYSTEM)\n"+      else "#define MK_JSVAL(x) (h$baseZCGHCziJSziPrimziJSVal_con_e, (x))\n"+  ,  "#define JSVAL_VAL(x) ((x).d1)\n"++  -- GHCJS.Prim.JSException+  , if profiling+      then "#define MK_JSEXCEPTION(msg,hsMsg) (h$c2(h$baseZCGHCziJSziPrimziJSException_con_e,(msg),(hsMsg),h$CCS_SYSTEM))\n"+      else "#define MK_JSEXCEPTION(msg,hsMsg) (h$c2(h$baseZCGHCziJSziPrimziJSException_con_e,(msg),(hsMsg)))\n"++  -- Exception dictionary for JSException+  , "#define HS_JSEXCEPTION_EXCEPTION h$baseZCGHCziJSziPrimzizdfExceptionJSException\n"++  -- SomeException+  , if profiling+      then "#define MK_SOMEEXCEPTION(dict,except) (h$c2(h$baseZCGHCziExceptionziTypeziSomeException_con_e,(dict),(except),h$CCS_SYSTEM))\n"+      else "#define MK_SOMEEXCEPTION(dict,except) (h$c2(h$baseZCGHCziExceptionziTypeziSomeException_con_e,(dict),(except)))\n"++  -- GHC.Ptr.Ptr+  , if profiling+      then "#define MK_PTR(val,offset) (h$c2(h$baseZCGHCziPtrziPtr_con_e, (val), (offset), h$CCS_SYSTEM))\n"+      else "#define MK_PTR(val,offset) (h$c2(h$baseZCGHCziPtrziPtr_con_e, (val), (offset)))\n"++  -- Data.Maybe.Maybe+  , "#define HS_NOTHING h$baseZCGHCziMaybeziNothing\n"+  , "#define IS_NOTHING(cl) ((cl).f === h$baseZCGHCziMaybeziNothing_con_e)\n"+  , "#define IS_JUST(cl) ((cl).f === h$baseZCGHCziMaybeziJust_con_e)\n"+  , "#define JUST_VAL(jj) ((jj).d1)\n"+  -- "#define HS_NOTHING h$nothing\n"+  , if profiling+      then "#define MK_JUST(val) (h$c1(h$baseZCGHCziMaybeziJust_con_e, (val), h$CCS_SYSTEM))\n"+      else "#define MK_JUST(val) (h$c1(h$baseZCGHCziMaybeziJust_con_e, (val)))\n"++  -- Data.List+  , "#define HS_NIL h$ghczmprimZCGHCziTypesziZMZN\n"+  , "#define HS_NIL_CON h$ghczmprimZCGHCziTypesziZMZN_con_e\n"+  , "#define IS_CONS(cl) ((cl).f === h$ghczmprimZCGHCziTypesziZC_con_e)\n"+  , "#define IS_NIL(cl) ((cl).f === h$ghczmprimZCGHCziTypesziZMZN_con_e)\n"+  , "#define CONS_HEAD(cl) ((cl).d1)\n"+  , "#define CONS_TAIL(cl) ((cl).d2)\n"+  , if profiling+      then mconcat+        [ "#define MK_CONS(head,tail) (h$c2(h$ghczmprimZCGHCziTypesziZC_con_e, (head), (tail), h$CCS_SYSTEM))\n"+        , "#define MK_CONS_CC(head,tail,cc) (h$c2(h$ghczmprimZCGHCziTypesziZC_con_e, (head), (tail), (cc)))\n"+        ]+      else mconcat+        [ "#define MK_CONS(head,tail) (h$c2(h$ghczmprimZCGHCziTypesziZC_con_e, (head), (tail)))\n"+        , "#define MK_CONS_CC(head,tail,cc) (h$c2(h$ghczmprimZCGHCziTypesziZC_con_e, (head), (tail)))\n"+        ]++  -- Data.Text+  , "#define DATA_TEXT_ARRAY(x) ((x).d1)\n"+  , "#define DATA_TEXT_OFFSET(x) ((x).d2.d1)\n"+  , "#define DATA_TEXT_LENGTH(x) ((x).d2.d2)\n"++  -- Data.Text.Lazy+  , "#define LAZY_TEXT_IS_CHUNK(x) ((x).f.a === 2)\n"+  , "#define LAZY_TEXT_IS_NIL(x) ((x).f.a === 1)\n"+  , "#define LAZY_TEXT_CHUNK_HEAD(x) ((x))\n"+  , "#define LAZY_TEXT_CHUNK_TAIL(x) ((x).d2.d3)\n"++  -- black holes+  -- can we skip the indirection for black holes?+  , "#define IS_BLACKHOLE(x) (typeof (x) === 'object' && (x) && (x).f && (x).f.t === CLOSURE_TYPE_BLACKHOLE)\n"+  , "#define BLACKHOLE_TID(bh) ((bh).d1)\n"+  , "#define SET_BLACKHOLE_TID(bh,tid) ((bh).d1 = (tid))\n"+  , "#define BLACKHOLE_QUEUE(bh) ((bh).d2)\n"+  , "#define SET_BLACKHOLE_QUEUE(bh,val) ((bh).d2 = (val))\n"++  -- resumable thunks+  , "#define MAKE_RESUMABLE(closure,stack) { (closure).f = h$resume_e; (closure).d1 = (stack), (closure).d2 = null; }\n"++  -- general deconstruction+  , "#define IS_THUNK(x) ((x).f.t === CLOSURE_TYPE_THUNK)\n"+  , "#define CONSTR_TAG(x) ((x).f.a)\n"++  -- retrieve a numeric value that's possibly stored as an indirection+  , "#define IS_WRAPPED_NUMBER(val) ((typeof(val)==='object')&&(val).f === h$unbox_e)\n"+  , "#define UNWRAP_NUMBER(val) ((typeof(val) === 'number')?(val):(val).d1)\n"++  -- generic lazy values+  , if profiling+      then mconcat+        [ "#define MK_LAZY(fun) (h$c1(h$lazy_e, (fun), h$CCS_SYSTEM))\n"+        , "#define MK_LAZY_CC(fun,cc) (h$c1(h$lazy_e, (fun), (cc)))\n"+        ]+      else mconcat+        [ "#define MK_LAZY(fun) (h$c1(h$lazy_e, (fun)))\n"+        , "#define MK_LAZY_CC(fun,cc) (h$c1(h$lazy_e, (fun)))\n"+        ]++  -- generic data constructors and selectors+  , if profiling+      then mconcat+        [ "#define MK_DATA1_1(val) (h$c1(h$data1_e, (val), h$CCS_SYSTEM))\n"+        , "#define MK_DATA1_2(val1,val2) (h$c2(h$data1_e, (val1), (val2), h$CCS_SYSTEM))\n"+        , "#define MK_DATA2_1(val) (h$c1(h$data2_e, (val), h$CCS_SYSTEM))\n"+        , "#define MK_DATA2_2(val1,val2) (h$c2(h$data1_e, (val1), (val2), h$CCS_SYSTEM))\n"+        , "#define MK_SELECT1(val) (h$c1(h$select1_e, (val), h$CCS_SYSTEM))\n"+        , "#define MK_SELECT2(val) (h$c1(h$select2_e, (val), h$CCS_SYSTEM))\n"+        , "#define MK_AP1(fun,val) (h$c2(h$ap1_e, (fun), (val), h$CCS_SYSTEM))\n"+        , "#define MK_AP2(fun,val1,val2) (h$c3(h$ap2_e, (fun), (val1), (val2), h$CCS_SYSTEM))\n"+        , "#define MK_AP3(fun,val1,val2,val3) (h$c4(h$ap3_e, (fun), (val1), (val2), (val3), h$CCS_SYSTEM))\n"+        ]+      else mconcat+        [ "#define MK_DATA1_1(val) (h$c1(h$data1_e, (val)))\n"+        , "#define MK_DATA1_2(val1,val2) (h$c2(h$data1_e, (val1), (val2)))\n"+        , "#define MK_DATA2_1(val) (h$c1(h$data2_e, (val)))\n"+        , "#define MK_DATA2_2(val1,val2) (h$c2(h$data2_e, (val1), (val2)))\n"+        , "#define MK_SELECT1(val) (h$c1(h$select1_e, (val)))\n"+        , "#define MK_SELECT2(val) (h$c1(h$select2_e, (val)))\n"+        , "#define MK_AP1(fun,val) (h$c2(h$ap1_e,(fun),(val)))\n"+        , "#define MK_AP2(fun,val1,val2) (h$c3(h$ap2_e,(fun),(val1),(val2)))\n"+        , "#define MK_AP3(fun,val1,val2,val3) (h$c4(h$ap3_e, (fun), (val1), (val2), (val3)))\n"+        ]++  -- unboxed tuple returns+  -- , "#define RETURN_UBX_TUP1(x) return x;\n"+  , "#define RETURN_UBX_TUP2(x1,x2) { h$ret1 = (x2); return (x1); }\n"+  , "#define RETURN_UBX_TUP3(x1,x2,x3) { h$ret1 = (x2); h$ret2 = (x3); return (x1); }\n"+  , "#define RETURN_UBX_TUP4(x1,x2,x3,x4) { h$ret1 = (x2); h$ret2 = (x3); h$ret3 = (x4); return (x1); }\n"+  , "#define RETURN_UBX_TUP5(x1,x2,x3,x4,x5) { h$ret1 = (x2); h$ret2 = (x3); h$ret3 = (x4); h$ret4 = (x5); return (x1); }\n"+  , "#define RETURN_UBX_TUP6(x1,x2,x3,x4,x5,x6) { h$ret1 = (x2); h$ret2 = (x3); h$ret3 = (x4); h$ret4 = (x5); h$ret5 = (x6); return (x1); }\n"+  , "#define RETURN_UBX_TUP7(x1,x2,x3,x4,x5,x6,x7) { h$ret1 = (x2); h$ret2 = (x3); h$ret3 = (x4); h$ret4 = (x5); h$ret5 = (x6); h$ret6 = (x7); return (x1); }\n"+  , "#define RETURN_UBX_TUP8(x1,x2,x3,x4,x5,x6,x7,x8) { h$ret1 = (x2); h$ret2 = (x3); h$ret3 = (x4); h$ret4 = (x5); h$ret5 = (x6); h$ret6 = (x7); h$ret7 = (x8); return (x1); }\n"+  , "#define RETURN_UBX_TUP9(x1,x2,x3,x4,x5,x6,x7,x8,x9) { h$ret1 = (x2); h$ret2 = (x3); h$ret3 = (x4); h$ret4 = (x5); h$ret5 = (x6); h$ret6 = (x7); h$ret7 = (x8); h$ret8 = (x9); return (x1); }\n"+  , "#define RETURN_UBX_TUP10(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10) { h$ret1 = (x2); h$ret2 = (x3); h$ret3 = (x4); h$ret4 = (x5); h$ret5 = (x6); h$ret6 = (x7); h$ret7 = (x8); h$ret8 = (x9); h$ret9 = (x10); return (x1); }\n"++  , "#define CALL_UBX_TUP2(r1,r2,c) { (r1) = (c); (r2) = h$ret1; }\n"+  , "#define CALL_UBX_TUP3(r1,r2,r3,c) { (r1) = (c); (r2) = h$ret1; (r3) = h$ret2; }\n"+  , "#define CALL_UBX_TUP4(r1,r2,r3,r4,c) { (r1) = (c); (r2) = h$ret1; (r3) = h$ret2; (r4) = h$ret3; }\n"+  , "#define CALL_UBX_TUP5(r1,r2,r3,r4,r5,c) { (r1) = (c); (r2) = h$ret1; (r3) = h$ret2; (r4) = h$ret3; (r5) = h$ret4; }\n"+  , "#define CALL_UBX_TUP6(r1,r2,r3,r4,r5,r6,c) { (r1) = (c); (r2) = h$ret1; (r3) = h$ret2; (r4) = h$ret3; (r5) = h$ret4; (r6) = h$ret5; }\n"+  , "#define CALL_UBX_TUP7(r1,r2,r3,r4,r5,r6,r7,c) { (r1) = (c); (r2) = h$ret1; (r3) = h$ret2; (r4) = h$ret3; (r5) = h$ret4; (r6) = h$ret5; (r7) = h$ret6; }\n"+  , "#define CALL_UBX_TUP8(r1,r2,r3,r4,r5,r6,r7,r8,c) { (r1) = (c); (r2) = h$ret1; (r3) = h$ret2; (r4) = h$ret3; (r5) = h$ret4; (r6) = h$ret5; (r7) = h$ret6; (r8) = h$ret7; }\n"+  , "#define CALL_UBX_TUP9(r1,r2,r3,r4,r5,r6,r7,r8,r9,c) { (r1) = (c); (r2) = h$ret1; (r3) = h$ret2; (r4) = h$ret3; (r5) = h$ret4; (r6) = h$ret5; (r7) = h$ret6; (r8) = h$ret7; (r9) = h$ret8; }\n"+  , "#define CALL_UBX_TUP10(r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,c) { (r1) = (c); (r2) = h$ret1; (r3) = h$ret2; (r4) = h$ret3; (r5) = h$ret4; (r6) = h$ret5; (r7) = h$ret6; (r8) = h$ret7; (r9) = h$ret8; (r10) = h$ret9; }\n"+  ]++-- | Construct the Filename for the "binary" of Haskell code compiled to+-- JavaScript.+jsExeFileName :: DynFlags -> FilePath+jsExeFileName dflags+  | Just s <- outputFile_ dflags =+      -- unmunge the extension+      let s' = dropPrefix "js_" (drop 1 $ takeExtension s)+      in if Prelude.null s'+           then dropExtension s <.> jsexeExtension+           else dropExtension s <.> s'+  | otherwise =+      if platformOS (targetPlatform dflags) == OSMinGW32+           then "main.jsexe"+           else "a.jsexe"+  where+    dropPrefix prefix xs+      | prefix `isPrefixOf` xs = drop (length prefix) xs+      | otherwise              = xs+++-- | Parse option pragma in JS file+getOptionsFromJsFile :: FilePath      -- ^ Input file+                     -> IO [JSOption] -- ^ Parsed options, if any.+getOptionsFromJsFile filename+    = Exception.bracket+              (openBinaryFile filename ReadMode)+              hClose+              getJsOptions++data JSOption = CPP deriving (Eq, Ord)++getJsOptions :: Handle -> IO [JSOption]+getJsOptions handle = do+  hSetEncoding handle utf8+  prefix' <- B.hGet handle prefixLen+  if prefix == prefix'+  then parseJsOptions <$> hGetLine handle+  else pure []+ where+  prefix :: B.ByteString+  prefix = "//#OPTIONS:"+  prefixLen = B.length prefix++parseJsOptions :: String -> [JSOption]+parseJsOptions xs = go xs+  where+    trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace+    go [] = []+    go xs = let (tok, rest) = break (== ',') xs+                tok' = trim tok+                rest' = drop 1 rest+            in  if | tok' == "CPP" -> CPP : go rest'+                   | otherwise     -> go rest'
+ compiler/GHC/StgToJS/Literal.hs view
@@ -0,0 +1,109 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module GHC.StgToJS.Literal+  ( genLit+  , genStaticLit+  )+where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Make++import GHC.StgToJS.Types+import GHC.StgToJS.Monad+import GHC.StgToJS.Ids+import GHC.StgToJS.Symbols++import GHC.Data.FastString+import GHC.Types.Literal+import GHC.Types.Basic+import GHC.Utils.Misc+import GHC.Utils.Panic+import GHC.Utils.Outputable+import GHC.Float++import Data.Bits as Bits+import Data.Char (ord)++-- | Generate JS expressions for a Literal+--+-- Literals represented with 2 values:+--  * Addr# (Null and Strings): array and offset+--  * 64-bit values: high 32-bit, low 32-bit+--  * labels: call to h$mkFunctionPtr and 0, or function name and 0+genLit :: HasDebugCallStack => Literal -> G [JExpr]+genLit = \case+  LitChar c     -> return [ toJExpr (ord c) ]+  LitString str ->+    freshIdent >>= \strLit@(TxtI strLitT) ->+      freshIdent >>= \strOff@(TxtI strOffT) -> do+        emitStatic strLitT (StaticUnboxed (StaticUnboxedString str)) Nothing+        emitStatic strOffT (StaticUnboxed (StaticUnboxedStringOffset str)) Nothing+        return [ ValExpr (JVar strLit), ValExpr (JVar strOff) ]+  LitNullAddr              -> return [ null_, ValExpr (JInt 0) ]+  LitNumber nt v           -> case nt of+    LitNumInt     -> return [ toJExpr v ]+    LitNumInt8    -> return [ toJExpr v ]+    LitNumInt16   -> return [ toJExpr v ]+    LitNumInt32   -> return [ toJExpr v ]+    LitNumInt64   -> return [ toJExpr (Bits.shiftR v 32), toU32Expr v ]+    LitNumWord    -> return [ toU32Expr v ]+    LitNumWord8   -> return [ toU32Expr v ]+    LitNumWord16  -> return [ toU32Expr v ]+    LitNumWord32  -> return [ toU32Expr v ]+    LitNumWord64  -> return [ toU32Expr (Bits.shiftR v 32), toU32Expr v ]+    LitNumBigNat  -> panic "genLit: unexpected BigNat that should have been removed in CorePrep"+  LitFloat r               -> return [ toJExpr (r2f r) ]+  LitDouble r              -> return [ toJExpr (r2d r) ]+  LitLabel name _size fod+    | fod == IsFunction      -> return [ ApplExpr (var "h$mkFunctionPtr")+                                                  [var (mkRawSymbol True name)]+                                       , ValExpr (JInt 0)+                                       ]+    | otherwise              -> return [ toJExpr (TxtI (mkRawSymbol True name))+                                       , ValExpr (JInt 0)+                                       ]+  LitRubbish {} -> return [ null_ ]++-- | generate a literal for the static init tables+genStaticLit :: Literal -> G [StaticLit]+genStaticLit = \case+  LitChar c                -> return [ IntLit (fromIntegral $ ord c) ]+  LitString str+    | True                 -> return [ StringLit (mkFastStringByteString str), IntLit 0]+    -- \|  invalid UTF8         -> return [ BinLit str, IntLit 0]+  LitNullAddr              -> return [ NullLit, IntLit 0 ]+  LitNumber nt v           -> case nt of+    LitNumInt     -> return [ IntLit v ]+    LitNumInt8    -> return [ IntLit v ]+    LitNumInt16   -> return [ IntLit v ]+    LitNumInt32   -> return [ IntLit v ]+    LitNumInt64   -> return [ IntLit (v `Bits.shiftR` 32), toU32Lit v ]+    LitNumWord    -> return [ toU32Lit v ]+    LitNumWord8   -> return [ toU32Lit v ]+    LitNumWord16  -> return [ toU32Lit v ]+    LitNumWord32  -> return [ toU32Lit v ]+    LitNumWord64  -> return [ toU32Lit (v `Bits.shiftR` 32), toU32Lit v ]+    LitNumBigNat  -> panic "genStaticLit: unexpected BigNat that should have been removed in CorePrep"+  LitFloat r               -> return [ DoubleLit . SaneDouble . r2f $ r ]+  LitDouble r              -> return [ DoubleLit . SaneDouble . r2d $ r ]+  LitLabel name _size fod  -> return [ LabelLit (fod == IsFunction) (mkRawSymbol True name)+                                     , IntLit 0 ]+  l -> pprPanic "genStaticLit" (ppr l)++-- make an unsigned 32 bit number from this unsigned one, lower 32 bits+toU32Expr :: Integer -> JExpr+toU32Expr i = Int (i Bits..&. 0xFFFFFFFF) .>>>. 0++-- make an unsigned 32 bit number from this unsigned one, lower 32 bits+toU32Lit :: Integer -> StaticLit+toU32Lit i = IntLit (i Bits..&. 0xFFFFFFFF)++r2d :: Rational -> Double+r2d = realToFrac++r2f :: Rational -> Double+r2f = float2Double . realToFrac
+ compiler/GHC/StgToJS/Monad.hs view
@@ -0,0 +1,183 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-}++-- | JS codegen state monad+module GHC.StgToJS.Monad+  ( runG+  , emitGlobal+  , addDependency+  , emitToplevel+  , emitStatic+  , emitClosureInfo+  , emitForeign+  , assertRtsStat+  , getSettings+  , globalOccs+  , setGlobalIdCache+  , getGlobalIdCache+  , GlobalOcc(..)+  -- * Group+  , modifyGroup+  , resetGroup+  )+where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Transform++import GHC.StgToJS.Types++import GHC.Unit.Module+import GHC.Stg.Syntax++import GHC.Types.SrcLoc+import GHC.Types.Id+import GHC.Types.Unique.FM+import GHC.Types.ForeignCall++import qualified Control.Monad.Trans.State.Strict as State+import GHC.Data.FastString+import GHC.Data.FastMutInt++import qualified Data.Map  as M+import qualified Data.Set  as S+import qualified Data.List as L++runG :: StgToJSConfig -> Module -> UniqFM Id CgStgExpr -> G a -> IO a+runG config m unfloat action = State.evalStateT action =<< initState config m unfloat++initState :: StgToJSConfig -> Module -> UniqFM Id CgStgExpr -> IO GenState+initState config m unfloat = do+  id_gen <- newFastMutInt 1+  pure $ GenState+    { gsSettings  = config+    , gsModule    = m+    , gsId        = id_gen+    , gsIdents    = emptyIdCache+    , gsUnfloated = unfloat+    , gsGroup     = defaultGenGroupState+    , gsGlobal    = []+    }+++modifyGroup :: (GenGroupState -> GenGroupState) -> G ()+modifyGroup f = State.modify mod_state+  where+    mod_state s = s { gsGroup = f (gsGroup s) }++-- | emit a global (for the current module) toplevel statement+emitGlobal :: JStat -> G ()+emitGlobal stat = State.modify (\s -> s { gsGlobal = stat : gsGlobal s })++-- | add a dependency on a particular symbol to the current group+addDependency :: OtherSymb -> G ()+addDependency symbol = modifyGroup mod_group+  where+    mod_group g = g { ggsExtraDeps = S.insert symbol (ggsExtraDeps g) }++-- | emit a top-level statement for the current binding group+emitToplevel :: JStat -> G ()+emitToplevel s = modifyGroup mod_group+  where+    mod_group g = g { ggsToplevelStats = s : ggsToplevelStats g}++-- | emit static data for the binding group+emitStatic :: FastString -> StaticVal -> Maybe Ident -> G ()+emitStatic ident val cc = modifyGroup mod_group+  where+    mod_group  g = g { ggsStatic = mod_static (ggsStatic g) }+    mod_static s = StaticInfo ident val cc : s++-- | add closure info in our binding group. all heap objects must have closure info+emitClosureInfo :: ClosureInfo -> G ()+emitClosureInfo ci = modifyGroup mod_group+  where+    mod_group g = g { ggsClosureInfo = ci : ggsClosureInfo g}++emitForeign :: Maybe RealSrcSpan+            -> FastString+            -> Safety+            -> CCallConv+            -> [FastString]+            -> FastString+            -> G ()+emitForeign mbSpan pat safety cconv arg_tys res_ty = modifyGroup mod_group+  where+    mod_group g = g { ggsForeignRefs = new_ref : ggsForeignRefs g }+    new_ref = ForeignJSRef spanTxt pat safety cconv arg_tys res_ty+    spanTxt = case mbSpan of+                -- TODO: Is there a better way to concatenate FastStrings?+                Just sp -> mkFastString $+                  unpackFS (srcSpanFile sp) +++                  " " +++                  show (srcSpanStartLine sp, srcSpanStartCol sp) +++                  "-" +++                  show (srcSpanEndLine sp, srcSpanEndCol sp)+                Nothing -> "<unknown>"+++++++-- | start with a new binding group+resetGroup :: G ()+resetGroup = State.modify (\s -> s { gsGroup = defaultGenGroupState })++defaultGenGroupState :: GenGroupState+defaultGenGroupState = GenGroupState [] [] [] [] 0 S.empty emptyGlobalIdCache []++emptyGlobalIdCache :: GlobalIdCache+emptyGlobalIdCache = GlobalIdCache emptyUFM++emptyIdCache :: IdCache+emptyIdCache = IdCache M.empty++++assertRtsStat :: G JStat -> G JStat+assertRtsStat stat = do+  s <- State.gets gsSettings+  if csAssertRts s then stat else pure mempty++getSettings :: G StgToJSConfig+getSettings = State.gets gsSettings++getGlobalIdCache :: G GlobalIdCache+getGlobalIdCache = State.gets (ggsGlobalIdCache . gsGroup)++setGlobalIdCache :: GlobalIdCache -> G ()+setGlobalIdCache v = State.modify (\s -> s { gsGroup = (gsGroup s) { ggsGlobalIdCache = v}})+++data GlobalOcc = GlobalOcc+  { global_ident :: !Ident+  , global_id    :: !Id+  , global_count :: !Word+  }++-- | Return number of occurrences of every global id used in the given JStat.+-- Sort by increasing occurrence count.+globalOccs :: JStat -> G [GlobalOcc]+globalOccs jst = do+  GlobalIdCache gidc <- getGlobalIdCache+  -- build a map form Ident Unique to (Ident, Id, Count)+  let+    cmp_cnt g1 g2 = compare (global_count g1) (global_count g2)+    inc g1 g2 = g1 { global_count = global_count g1 + global_count g2 }+    go gids = \case+        []     -> -- return global Ids used locally sorted by increased use+                  L.sortBy cmp_cnt $ nonDetEltsUFM gids+        (i:is) ->+          -- check if the Id is global+          case lookupUFM gidc i of+            Nothing       -> go gids is+            Just (_k,gid) ->+              -- add it to the list of already found global ids. Increasing+              -- count by 1+              let g = GlobalOcc i gid 1+              in go (addToUFM_C inc gids i g) is++  pure $ go emptyUFM (identsS jst)
+ compiler/GHC/StgToJS/Object.hs view
@@ -0,0 +1,622 @@+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE LambdaCase                 #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE Rank2Types                 #-}+{-# LANGUAGE ScopedTypeVariables        #-}++-- only for DB.Binary instances on Module+{-# OPTIONS_GHC -fno-warn-orphans #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Object+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Sylvain Henry  <sylvain.henry@iohk.io>+--                Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+--  Serialization/deserialization of binary .o files for the JavaScript backend+--  The .o files contain dependency information and generated code.+--  All strings are mapped to a central string table, which helps reduce+--  file size and gives us efficient hash consing on read+--+--  Binary intermediate JavaScript object files:+--   serialized [Text] -> ([ClosureInfo], JStat) blocks+--+--  file layout:+--   - magic "GHCJSOBJ"+--   - compiler version tag+--   - module name+--   - offsets of string table+--   - dependencies+--   - offset of the index+--   - unit infos+--   - index+--   - string table+--+-----------------------------------------------------------------------------++module GHC.StgToJS.Object+  ( putObject+  , getObjectHeader+  , getObjectBody+  , getObject+  , readObject+  , getObjectUnits+  , readObjectUnits+  , readObjectDeps+  , isGlobalUnit+  , isJsObjectFile+  , Object(..)+  , IndexEntry(..)+  , Deps (..), BlockDeps (..), DepsLocation (..)+  , ExportedFun (..)+  )+where++import GHC.Prelude++import           Control.Monad++import           Data.Array+import           Data.Int+import           Data.IntSet (IntSet)+import qualified Data.IntSet as IS+import           Data.List (sortOn)+import           Data.Map (Map)+import qualified Data.Map as M+import           Data.Word+import           Data.Char+import Foreign.Storable+import Foreign.Marshal.Array+import System.IO++import GHC.Settings.Constants (hiVersion)++import GHC.JS.Syntax+import GHC.StgToJS.Types++import GHC.Unit.Module++import GHC.Data.FastString++import GHC.Types.Unique.Map+import GHC.Float (castDoubleToWord64, castWord64ToDouble)++import GHC.Utils.Binary hiding (SymbolTable)+import GHC.Utils.Outputable (ppr, Outputable, hcat, vcat, text, hsep)+import GHC.Utils.Monad (mapMaybeM)++-- | An object file+data Object = Object+  { objModuleName    :: !ModuleName+    -- ^ name of the module+  , objHandle        :: !BinHandle+    -- ^ BinHandle that can be used to read the ObjUnits+  , objPayloadOffset :: !(Bin ObjUnit)+    -- ^ Offset of the payload (units)+  , objDeps          :: !Deps+    -- ^ Dependencies+  , objIndex         :: !Index+    -- ^ The Index, serialed unit indices and their linkable units+  }++type BlockId  = Int+type BlockIds = IntSet++-- | dependencies for a single module+data Deps = Deps+  { depsModule          :: !Module+      -- ^ module+  , depsRequired        :: !BlockIds+      -- ^ blocks that always need to be linked when this object is loaded (e.g.+      -- everything that contains initializer code or foreign exports)+  , depsHaskellExported :: !(Map ExportedFun BlockId)+      -- ^ exported Haskell functions -> block+  , depsBlocks          :: !(Array BlockId BlockDeps)+      -- ^ info about each block+  }++instance Outputable Deps where+  ppr d = vcat+    [ hcat [ text "module: ", pprModule (depsModule d) ]+    , hcat [ text "exports: ", ppr (M.keys (depsHaskellExported d)) ]+    ]++-- | Where are the dependencies+data DepsLocation+  = ObjectFile  FilePath       -- ^ In an object file at path+  | ArchiveFile FilePath       -- ^ In a Ar file at path+  | InMemory    String Object  -- ^ In memory++instance Outputable DepsLocation where+  ppr = \case+    ObjectFile fp  -> hsep [text "ObjectFile", text fp]+    ArchiveFile fp -> hsep [text "ArchiveFile", text fp]+    InMemory s o   -> hsep [text "InMemory", text s, ppr (objModuleName o)]++data BlockDeps = BlockDeps+  { blockBlockDeps       :: [Int]         -- ^ dependencies on blocks in this object+  , blockFunDeps         :: [ExportedFun] -- ^ dependencies on exported symbols in other objects+  -- , blockForeignExported :: [ExpFun]+  -- , blockForeignImported :: [ForeignRef]+  }++{- | we use the convention that the first unit (0) is a module-global+     unit that's always included when something from the module+     is loaded. everything in a module implicitly depends on the+     global block. the global unit itself can't have dependencies+ -}+isGlobalUnit :: Int -> Bool+isGlobalUnit n = n == 0++-- | Exported Functions+data ExportedFun = ExportedFun+  { funModule  :: !Module              -- ^ The module containing the function+  , funSymbol  :: !LexicalFastString   -- ^ The function+  } deriving (Eq, Ord)++instance Outputable ExportedFun where+  ppr (ExportedFun m f) = vcat+    [ hcat [ text "module: ", pprModule m ]+    , hcat [ text "symbol: ", ppr f ]+    ]++-- | Write an ObjUnit, except for the top level symbols which are stored in the+-- index+putObjUnit :: BinHandle -> ObjUnit -> IO ()+putObjUnit bh (ObjUnit _syms b c d e f g) = do+    put_ bh b+    put_ bh c+    lazyPut bh d+    put_ bh e+    put_ bh f+    put_ bh g++-- | Read an ObjUnit and associate it to the given symbols (that must have been+-- read from the index)+getObjUnit :: [FastString] -> BinHandle -> IO ObjUnit+getObjUnit syms bh = do+    b <- get bh+    c <- get bh+    d <- lazyGet bh+    e <- get bh+    f <- get bh+    g <- get bh+    pure $ ObjUnit+      { oiSymbols  = syms+      , oiClInfo   = b+      , oiStatic   = c+      , oiStat     = d+      , oiRaw      = e+      , oiFExports = f+      , oiFImports = g+      }+++-- | A tag that determines the kind of payload in the .o file. See+-- @StgToJS.Linker.Arhive.magic@ for another kind of magic+magic :: String+magic = "GHCJSOBJ"++-- | Serialized unit indexes and their exported symbols+-- (the first unit is module-global)+type Index = [IndexEntry]+data IndexEntry = IndexEntry+  { idxSymbols :: ![FastString]  -- ^ Symbols exported by a unit+  , idxOffset  :: !(Bin ObjUnit) -- ^ Offset of the unit in the object file+  }+++--------------------------------------------------------------------------------+-- Essential oeprations on Objects+--------------------------------------------------------------------------------++-- | Given a handle to a Binary payload, add the module, 'mod_name', its+-- dependencies, 'deps', and its linkable units to the payload.+putObject+  :: BinHandle+  -> ModuleName -- ^ module+  -> Deps       -- ^ dependencies+  -> [ObjUnit]  -- ^ linkable units and their symbols+  -> IO ()+putObject bh mod_name deps os = do+  forM_ magic (putByte bh . fromIntegral . ord)+  put_ bh (show hiVersion)++  -- we store the module name as a String because we don't want to have to+  -- decode the FastString table just to decode it when we're looking for an+  -- object in an archive.+  put_ bh (moduleNameString mod_name)++  (bh_fs, _bin_dict, put_dict) <- initFSTable bh++  forwardPut_ bh (const put_dict) $ do+    put_ bh_fs deps++    -- forward put the index+    forwardPut_ bh_fs (put_ bh_fs) $ do+      idx <- forM os $ \o -> do+        p <- tellBin bh_fs+        -- write units without their symbols+        putObjUnit bh_fs o+        -- return symbols and offset to store in the index+        pure (oiSymbols o,p)+      pure idx++-- | Test if the object file is a JS object+isJsObjectFile :: FilePath -> IO Bool+isJsObjectFile fp = do+  let !n = length magic+  withBinaryFile fp ReadMode $ \hdl -> do+    allocaArray n $ \ptr -> do+      n' <- hGetBuf hdl ptr n+      if (n' /= n)+        then pure False+        else checkMagic (peekElemOff ptr)++-- | Check magic+checkMagic :: (Int -> IO Word8) -> IO Bool+checkMagic get_byte = do+  let go_magic !i = \case+        []     -> pure True+        (e:es) -> get_byte i >>= \case+          c | fromIntegral (ord e) == c -> go_magic (i+1) es+            | otherwise                 -> pure False+  go_magic 0 magic++-- | Parse object magic+getCheckMagic :: BinHandle -> IO Bool+getCheckMagic bh = checkMagic (const (getByte bh))++-- | Parse object header+getObjectHeader :: BinHandle -> IO (Either String ModuleName)+getObjectHeader bh = do+  is_magic <- getCheckMagic bh+  case is_magic of+    False -> pure (Left "invalid magic header")+    True  -> do+      is_correct_version <- ((== hiVersion) . read) <$> get bh+      case is_correct_version of+        False -> pure (Left "invalid header version")+        True  -> do+          mod_name <- get bh+          pure (Right (mkModuleName (mod_name)))+++-- | Parse object body. Must be called after a sucessful getObjectHeader+getObjectBody :: BinHandle -> ModuleName -> IO Object+getObjectBody bh0 mod_name = do+  -- Read the string table+  dict <- forwardGet bh0 (getDictionary bh0)+  let bh = setUserData bh0 $ noUserData { ud_get_fs = getDictFastString dict }++  deps     <- get bh+  idx      <- forwardGet bh (get bh)+  payload_pos <- tellBin bh++  pure $ Object+    { objModuleName    = mod_name+    , objHandle        = bh+    , objPayloadOffset = payload_pos+    , objDeps          = deps+    , objIndex         = idx+    }++-- | Parse object+getObject :: BinHandle -> IO (Maybe Object)+getObject bh = do+  getObjectHeader bh >>= \case+    Left _err      -> pure Nothing+    Right mod_name -> Just <$> getObjectBody bh mod_name++-- | Read object from file+--+-- The object is still in memory after this (see objHandle).+readObject :: FilePath -> IO (Maybe Object)+readObject file = do+  bh <- readBinMem file+  getObject bh++-- | Reads only the part necessary to get the dependencies+readObjectDeps :: FilePath -> IO (Maybe Deps)+readObjectDeps file = do+  bh <- readBinMem file+  getObject bh >>= \case+    Just obj -> pure $! Just $! objDeps obj+    Nothing  -> pure Nothing++-- | Get units in the object file, using the given filtering function+getObjectUnits :: Object -> (Word -> IndexEntry -> Bool) -> IO [ObjUnit]+getObjectUnits obj pred = mapMaybeM read_entry (zip (objIndex obj) [0..])+  where+    bh = objHandle obj+    read_entry (e@(IndexEntry syms offset),i)+      | pred i e  = do+          seekBin bh offset+          Just <$> getObjUnit syms bh+      | otherwise = pure Nothing++-- | Read units in the object file, using the given filtering function+readObjectUnits :: FilePath -> (Word -> IndexEntry -> Bool) -> IO [ObjUnit]+readObjectUnits file pred = do+  readObject file >>= \case+    Nothing  -> pure []+    Just obj -> getObjectUnits obj pred+++--------------------------------------------------------------------------------+-- Helper functions+--------------------------------------------------------------------------------++putEnum :: Enum a => BinHandle -> a -> IO ()+putEnum bh x | n > 65535 = error ("putEnum: out of range: " ++ show n)+             | otherwise = put_ bh n+  where n = fromIntegral $ fromEnum x :: Word16++getEnum :: Enum a => BinHandle -> IO a+getEnum bh = toEnum . fromIntegral <$> (get bh :: IO Word16)++-- | Helper to convert Int to Int32+toI32 :: Int -> Int32+toI32 = fromIntegral++-- | Helper to convert Int32 to Int+fromI32 :: Int32 -> Int+fromI32 = fromIntegral+++--------------------------------------------------------------------------------+-- Binary Instances+--------------------------------------------------------------------------------++instance Binary IndexEntry where+  put_ bh (IndexEntry a b) = put_ bh a >> put_ bh b+  get bh = IndexEntry <$> get bh <*> get bh++instance Binary Deps where+  put_ bh (Deps m r e b) = do+      put_ bh m+      put_ bh (map toI32 $ IS.toList r)+      put_ bh (map (\(x,y) -> (x, toI32 y)) $ M.toList e)+      put_ bh (elems b)+  get bh = Deps <$> get bh+             <*> (IS.fromList . map fromI32 <$> get bh)+             <*> (M.fromList . map (\(x,y) -> (x, fromI32 y)) <$> get bh)+             <*> ((\xs -> listArray (0, length xs - 1) xs) <$> get bh)++instance Binary BlockDeps where+  put_ bh (BlockDeps bbd bfd) = put_ bh bbd >> put_ bh bfd+  get bh = BlockDeps <$> get bh <*> get bh++instance Binary ForeignJSRef where+  put_ bh (ForeignJSRef span pat safety cconv arg_tys res_ty) =+    put_ bh span >> put_ bh pat >> putEnum bh safety >> putEnum bh cconv >> put_ bh arg_tys >> put_ bh res_ty+  get bh = ForeignJSRef <$> get bh <*> get bh <*> getEnum bh <*> getEnum bh <*> get bh <*> get bh++instance Binary ExpFun where+  put_ bh (ExpFun isIO args res) = put_ bh isIO >> put_ bh args >> put_ bh res+  get bh                        = ExpFun <$> get bh <*> get bh <*> get bh++instance Binary JStat where+  put_ bh (DeclStat i e)       = putByte bh 1  >> put_ bh i >> put_ bh e+  put_ bh (ReturnStat e)       = putByte bh 2  >> put_ bh e+  put_ bh (IfStat e s1 s2)     = putByte bh 3  >> put_ bh e  >> put_ bh s1 >> put_ bh s2+  put_ bh (WhileStat b e s)    = putByte bh 4  >> put_ bh b  >> put_ bh e  >> put_ bh s+  put_ bh (ForInStat b i e s)  = putByte bh 5  >> put_ bh b  >> put_ bh i  >> put_ bh e  >> put_ bh s+  put_ bh (SwitchStat e ss s)  = putByte bh 6  >> put_ bh e  >> put_ bh ss >> put_ bh s+  put_ bh (TryStat s1 i s2 s3) = putByte bh 7  >> put_ bh s1 >> put_ bh i  >> put_ bh s2 >> put_ bh s3+  put_ bh (BlockStat xs)       = putByte bh 8  >> put_ bh xs+  put_ bh (ApplStat e es)      = putByte bh 9  >> put_ bh e  >> put_ bh es+  put_ bh (UOpStat o e)        = putByte bh 10 >> put_ bh o  >> put_ bh e+  put_ bh (AssignStat e1 e2)   = putByte bh 11 >> put_ bh e1 >> put_ bh e2+  put_ _  (UnsatBlock {})      = error "put_ bh JStat: UnsatBlock"+  put_ bh (LabelStat l s)      = putByte bh 12 >> put_ bh l  >> put_ bh s+  put_ bh (BreakStat ml)       = putByte bh 13 >> put_ bh ml+  put_ bh (ContinueStat ml)    = putByte bh 14 >> put_ bh ml+  get bh = getByte bh >>= \case+    1  -> DeclStat     <$> get bh <*> get bh+    2  -> ReturnStat   <$> get bh+    3  -> IfStat       <$> get bh <*> get bh <*> get bh+    4  -> WhileStat    <$> get bh <*> get bh <*> get bh+    5  -> ForInStat    <$> get bh <*> get bh <*> get bh <*> get bh+    6  -> SwitchStat   <$> get bh <*> get bh <*> get bh+    7  -> TryStat      <$> get bh <*> get bh <*> get bh <*> get bh+    8  -> BlockStat    <$> get bh+    9  -> ApplStat     <$> get bh <*> get bh+    10 -> UOpStat      <$> get bh <*> get bh+    11 -> AssignStat   <$> get bh <*> get bh+    12 -> LabelStat    <$> get bh <*> get bh+    13 -> BreakStat    <$> get bh+    14 -> ContinueStat <$> get bh+    n -> error ("Binary get bh JStat: invalid tag: " ++ show n)++instance Binary JExpr where+  put_ bh (ValExpr v)          = putByte bh 1 >> put_ bh v+  put_ bh (SelExpr e i)        = putByte bh 2 >> put_ bh e  >> put_ bh i+  put_ bh (IdxExpr e1 e2)      = putByte bh 3 >> put_ bh e1 >> put_ bh e2+  put_ bh (InfixExpr o e1 e2)  = putByte bh 4 >> put_ bh o  >> put_ bh e1 >> put_ bh e2+  put_ bh (UOpExpr o e)        = putByte bh 5 >> put_ bh o  >> put_ bh e+  put_ bh (IfExpr e1 e2 e3)    = putByte bh 6 >> put_ bh e1 >> put_ bh e2 >> put_ bh e3+  put_ bh (ApplExpr e es)      = putByte bh 7 >> put_ bh e  >> put_ bh es+  put_ _  (UnsatExpr {})       = error "put_ bh JExpr: UnsatExpr"+  get bh = getByte bh >>= \case+    1 -> ValExpr   <$> get bh+    2 -> SelExpr   <$> get bh <*> get bh+    3 -> IdxExpr   <$> get bh <*> get bh+    4 -> InfixExpr <$> get bh <*> get bh <*> get bh+    5 -> UOpExpr   <$> get bh <*> get bh+    6 -> IfExpr    <$> get bh <*> get bh <*> get bh+    7 -> ApplExpr  <$> get bh <*> get bh+    n -> error ("Binary get bh JExpr: invalid tag: " ++ show n)++instance Binary JVal where+  put_ bh (JVar i)      = putByte bh 1 >> put_ bh i+  put_ bh (JList es)    = putByte bh 2 >> put_ bh es+  put_ bh (JDouble d)   = putByte bh 3 >> put_ bh d+  put_ bh (JInt i)      = putByte bh 4 >> put_ bh i+  put_ bh (JStr xs)     = putByte bh 5 >> put_ bh xs+  put_ bh (JRegEx xs)   = putByte bh 6 >> put_ bh xs+  put_ bh (JHash m)     = putByte bh 7 >> put_ bh (sortOn (LexicalFastString . fst) $ nonDetEltsUniqMap m)+  put_ bh (JFunc is s)  = putByte bh 8 >> put_ bh is >> put_ bh s+  put_ _  (UnsatVal {}) = error "put_ bh JVal: UnsatVal"+  get bh = getByte bh >>= \case+    1 -> JVar    <$> get bh+    2 -> JList   <$> get bh+    3 -> JDouble <$> get bh+    4 -> JInt    <$> get bh+    5 -> JStr    <$> get bh+    6 -> JRegEx  <$> get bh+    7 -> JHash . listToUniqMap <$> get bh+    8 -> JFunc   <$> get bh <*> get bh+    n -> error ("Binary get bh JVal: invalid tag: " ++ show n)++instance Binary Ident where+  put_ bh (TxtI xs) = put_ bh xs+  get bh = TxtI <$> get bh++-- we need to preserve NaN and infinities, unfortunately the Binary instance for Double does not do this+instance Binary SaneDouble where+  put_ bh (SaneDouble d)+    | isNaN d               = putByte bh 1+    | isInfinite d && d > 0 = putByte bh 2+    | isInfinite d && d < 0 = putByte bh 3+    | isNegativeZero d      = putByte bh 4+    | otherwise             = putByte bh 5 >> put_ bh (castDoubleToWord64 d)+  get bh = getByte bh >>= \case+    1 -> pure $ SaneDouble (0    / 0)+    2 -> pure $ SaneDouble (1    / 0)+    3 -> pure $ SaneDouble ((-1) / 0)+    4 -> pure $ SaneDouble (-0)+    5 -> SaneDouble . castWord64ToDouble <$> get bh+    n -> error ("Binary get bh SaneDouble: invalid tag: " ++ show n)++instance Binary ClosureInfo where+  put_ bh (ClosureInfo v regs name layo typ static) = do+    put_ bh v >> put_ bh regs >> put_ bh name >> put_ bh layo >> put_ bh typ >> put_ bh static+  get bh = ClosureInfo <$> get bh <*> get bh <*> get bh <*> get bh <*> get bh <*> get bh++instance Binary JSFFIType where+  put_ bh = putEnum bh+  get bh = getEnum bh++instance Binary VarType where+  put_ bh = putEnum bh+  get bh = getEnum bh++instance Binary CIRegs where+  put_ bh CIRegsUnknown       = putByte bh 1+  put_ bh (CIRegs skip types) = putByte bh 2 >> put_ bh skip >> put_ bh types+  get bh = getByte bh >>= \case+    1 -> pure CIRegsUnknown+    2 -> CIRegs <$> get bh <*> get bh+    n -> error ("Binary get bh CIRegs: invalid tag: " ++ show n)++instance Binary JOp where+  put_ bh = putEnum bh+  get bh = getEnum bh++instance Binary JUOp where+  put_ bh = putEnum bh+  get bh = getEnum bh++-- 16 bit sizes should be enough...+instance Binary CILayout where+  put_ bh CILayoutVariable           = putByte bh 1+  put_ bh (CILayoutUnknown size)     = putByte bh 2 >> put_ bh size+  put_ bh (CILayoutFixed size types) = putByte bh 3 >> put_ bh size >> put_ bh types+  get bh = getByte bh >>= \case+    1 -> pure CILayoutVariable+    2 -> CILayoutUnknown <$> get bh+    3 -> CILayoutFixed   <$> get bh <*> get bh+    n -> error ("Binary get bh CILayout: invalid tag: " ++ show n)++instance Binary CIStatic where+  put_ bh (CIStaticRefs refs) = putByte bh 1 >> put_ bh refs+  get bh = getByte bh >>= \case+    1 -> CIStaticRefs <$> get bh+    n -> error ("Binary get bh CIStatic: invalid tag: " ++ show n)++instance Binary CIType where+  put_ bh (CIFun arity regs) = putByte bh 1 >> put_ bh arity >> put_ bh regs+  put_ bh CIThunk            = putByte bh 2+  put_ bh (CICon conTag)     = putByte bh 3 >> put_ bh conTag+  put_ bh CIPap              = putByte bh 4+  put_ bh CIBlackhole        = putByte bh 5+  put_ bh CIStackFrame       = putByte bh 6+  get bh = getByte bh >>= \case+    1 -> CIFun <$> get bh <*> get bh+    2 -> pure CIThunk+    3 -> CICon <$> get bh+    4 -> pure CIPap+    5 -> pure CIBlackhole+    6 -> pure CIStackFrame+    n -> error ("Binary get bh CIType: invalid tag: " ++ show n)++instance Binary ExportedFun where+  put_ bh (ExportedFun modu symb) = put_ bh modu >> put_ bh symb+  get bh = ExportedFun <$> get bh <*> get bh++instance Binary StaticInfo where+  put_ bh (StaticInfo ident val cc) = put_ bh ident >> put_ bh val >> put_ bh cc+  get bh = StaticInfo <$> get bh <*> get bh <*> get bh++instance Binary StaticVal where+  put_ bh (StaticFun f args)   = putByte bh 1 >> put_ bh f  >> put_ bh args+  put_ bh (StaticThunk t)      = putByte bh 2 >> put_ bh t+  put_ bh (StaticUnboxed u)    = putByte bh 3 >> put_ bh u+  put_ bh (StaticData dc args) = putByte bh 4 >> put_ bh dc >> put_ bh args+  put_ bh (StaticList xs t)    = putByte bh 5 >> put_ bh xs >> put_ bh t+  get bh = getByte bh >>= \case+    1 -> StaticFun     <$> get bh <*> get bh+    2 -> StaticThunk   <$> get bh+    3 -> StaticUnboxed <$> get bh+    4 -> StaticData    <$> get bh <*> get bh+    5 -> StaticList    <$> get bh <*> get bh+    n -> error ("Binary get bh StaticVal: invalid tag " ++ show n)++instance Binary StaticUnboxed where+  put_ bh (StaticUnboxedBool b)           = putByte bh 1 >> put_ bh b+  put_ bh (StaticUnboxedInt i)            = putByte bh 2 >> put_ bh i+  put_ bh (StaticUnboxedDouble d)         = putByte bh 3 >> put_ bh d+  put_ bh (StaticUnboxedString str)       = putByte bh 4 >> put_ bh str+  put_ bh (StaticUnboxedStringOffset str) = putByte bh 5 >> put_ bh str+  get bh = getByte bh >>= \case+    1 -> StaticUnboxedBool         <$> get bh+    2 -> StaticUnboxedInt          <$> get bh+    3 -> StaticUnboxedDouble       <$> get bh+    4 -> StaticUnboxedString       <$> get bh+    5 -> StaticUnboxedStringOffset <$> get bh+    n -> error ("Binary get bh StaticUnboxed: invalid tag " ++ show n)++instance Binary StaticArg where+  put_ bh (StaticObjArg i)      = putByte bh 1 >> put_ bh i+  put_ bh (StaticLitArg p)      = putByte bh 2 >> put_ bh p+  put_ bh (StaticConArg c args) = putByte bh 3 >> put_ bh c >> put_ bh args+  get bh = getByte bh >>= \case+    1 -> StaticObjArg <$> get bh+    2 -> StaticLitArg <$> get bh+    3 -> StaticConArg <$> get bh <*> get bh+    n -> error ("Binary get bh StaticArg: invalid tag " ++ show n)++instance Binary StaticLit where+  put_ bh (BoolLit b)    = putByte bh 1 >> put_ bh b+  put_ bh (IntLit i)     = putByte bh 2 >> put_ bh i+  put_ bh NullLit        = putByte bh 3+  put_ bh (DoubleLit d)  = putByte bh 4 >> put_ bh d+  put_ bh (StringLit t)  = putByte bh 5 >> put_ bh t+  put_ bh (BinLit b)     = putByte bh 6 >> put_ bh b+  put_ bh (LabelLit b t) = putByte bh 7 >> put_ bh b >> put_ bh t+  get bh = getByte bh >>= \case+    1 -> BoolLit   <$> get bh+    2 -> IntLit    <$> get bh+    3 -> pure NullLit+    4 -> DoubleLit <$> get bh+    5 -> StringLit <$> get bh+    6 -> BinLit    <$> get bh+    7 -> LabelLit  <$> get bh <*> get bh+    n -> error ("Binary get bh StaticLit: invalid tag " ++ show n)
+ compiler/GHC/StgToJS/Prim.hs view
@@ -0,0 +1,1509 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE MultiWayIf #-}++-- disable this warning because of all the lambdas matching on primops'+-- arguments.+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}++module GHC.StgToJS.Prim+  ( genPrim+  )+where++import GHC.Prelude++import GHC.JS.Syntax hiding (JUOp (..))+import GHC.JS.Make++import GHC.StgToJS.Heap+import GHC.StgToJS.Types+import GHC.StgToJS.Profiling+import GHC.StgToJS.Regs++import GHC.Core.Type++import GHC.Builtin.PrimOps+import GHC.Tc.Utils.TcType (isBoolTy)+import GHC.Utils.Encoding (zEncodeString)++import GHC.Data.FastString+import GHC.Utils.Outputable (renderWithContext, defaultSDocContext, ppr)+import Data.Maybe+++genPrim :: Bool     -- ^ Profiling (cost-centres) enabled+        -> Bool     -- ^ Array bounds-checking enabled+        -> Type+        -> PrimOp   -- ^ the primitive operation+        -> [JExpr]  -- ^ where to store the result+        -> [JExpr]  -- ^ arguments+        -> PrimRes+genPrim prof bound ty op = case op of+  CharGtOp        -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>. y)+  CharGeOp        -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>=. y)+  CharEqOp        -> \[r] [x,y] -> PrimInline $ r |= if10 (x .===. y)+  CharNeOp        -> \[r] [x,y] -> PrimInline $ r |= if10 (x .!==. y)+  CharLtOp        -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<. y)+  CharLeOp        -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<=. y)+  OrdOp           -> \[r] [x]   -> PrimInline $ r |= x++  Int8ToWord8Op   -> \[r] [x]   -> PrimInline $ r |= mask8 x+  Word8ToInt8Op   -> \[r] [x]   -> PrimInline $ r |= signExtend8 x+  Int16ToWord16Op -> \[r] [x]   -> PrimInline $ r |= mask16 x+  Word16ToInt16Op -> \[r] [x]   -> PrimInline $ r |= signExtend16 x+  Int32ToWord32Op -> \[r] [x]   -> PrimInline $ r |= x .>>>. zero_+  Word32ToInt32Op -> \[r] [x]   -> PrimInline $ r |= toI32 x++------------------------------ Int ----------------------------------------------++  IntAddOp        -> \[r] [x,y] -> PrimInline $ r |= toI32 (Add x y)+  IntSubOp        -> \[r] [x,y] -> PrimInline $ r |= toI32 (Sub x y)+  IntMulOp        -> \[r] [x,y] -> PrimInline $ r |= app "h$mulInt32" [x, y]+  IntMul2Op       -> \[c,hr,lr] [x,y] -> PrimInline $ appT [c,hr,lr] "h$hs_timesInt2" [x, y]+  IntMulMayOfloOp -> \[r] [x,y] -> PrimInline $ jVar \tmp -> mconcat+                                            [ tmp |= Mul x y+                                            , r   |= if01 (tmp .===. toI32 tmp)+                                            ]+  IntQuotOp       -> \[r]   [x,y] -> PrimInline $ r |= toI32 (Div x y)+  IntRemOp        -> \[r]   [x,y] -> PrimInline $ r |= Mod x y+  IntQuotRemOp    -> \[q,r] [x,y] -> PrimInline $ mconcat+                                            [ q |= toI32 (Div x y)+                                            , r |= x `Sub` (Mul y q)+                                            ]+  IntAndOp        -> \[r] [x,y]   -> PrimInline $ r |= BAnd x y+  IntOrOp         -> \[r] [x,y]   -> PrimInline $ r |= BOr  x y+  IntXorOp        -> \[r] [x,y]   -> PrimInline $ r |= BXor x y+  IntNotOp        -> \[r] [x]     -> PrimInline $ r |= BNot x++  IntNegOp        -> \[r] [x]   -> PrimInline $ r |= toI32 (Negate x)+-- add with carry: overflow == 0 iff no overflow+  IntAddCOp       -> \[r,overf] [x,y] ->+      PrimInline $ jVar \rt -> mconcat+        [ rt    |= Add x y+        , r     |= toI32 rt+        , overf |= if10 (r .!=. rt)+        ]+  IntSubCOp       -> \[r,overf] [x,y] ->+      PrimInline $ jVar \rt -> mconcat+        [ rt    |= Sub x y+        , r     |= toI32 rt+        , overf |= if10 (r .!=. rt)+        ]+  IntGtOp           -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>. y)+  IntGeOp           -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>=. y)+  IntEqOp           -> \[r] [x,y] -> PrimInline $ r |= if10 (x .===. y)+  IntNeOp           -> \[r] [x,y] -> PrimInline $ r |= if10(x .!==. y)+  IntLtOp           -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<. y)+  IntLeOp           -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<=. y)+  ChrOp             -> \[r] [x]   -> PrimInline $ r |= x+  IntToWordOp       -> \[r] [x]   -> PrimInline $ r |= x .>>>. 0+  IntToFloatOp      -> \[r] [x]   -> PrimInline $ r |= x+  IntToDoubleOp     -> \[r] [x]   -> PrimInline $ r |= x+  IntSllOp          -> \[r] [x,y] -> PrimInline $ r |= x .<<. y+  IntSraOp          -> \[r] [x,y] -> PrimInline $ r |= x .>>. y+  IntSrlOp          -> \[r] [x,y] -> PrimInline $ r |= toI32 (x .>>>. y)++------------------------------ Int8 ---------------------------------------------++  Int8ToIntOp       -> \[r] [x]       -> PrimInline $ r |= x+  IntToInt8Op       -> \[r] [x]       -> PrimInline $ r |= signExtend8 x+  Int8NegOp         -> \[r] [x]       -> PrimInline $ r |= signExtend8 (Negate x)+  Int8AddOp         -> \[r] [x,y]     -> PrimInline $ r |= signExtend8 (Add x y)+  Int8SubOp         -> \[r] [x,y]     -> PrimInline $ r |= signExtend8 (Sub x y)+  Int8MulOp         -> \[r] [x,y]     -> PrimInline $ r |= signExtend8 (Mul x y)+  Int8QuotOp        -> \[r] [x,y]     -> PrimInline $ r |= signExtend8 (quotShortInt 8 x y)+  Int8RemOp         -> \[r] [x,y]     -> PrimInline $ r |= signExtend8 (remShortInt 8 x y)+  Int8QuotRemOp     -> \[r1,r2] [x,y] -> PrimInline $ mconcat+                                                [ r1 |= signExtend8 (quotShortInt 8 x y)+                                                , r2 |= signExtend8 (remShortInt 8 x y)+                                                ]+  Int8EqOp          -> \[r] [x,y] -> PrimInline $ r |= if10 (x .===. y)+  Int8GeOp          -> \[r] [x,y] -> PrimInline $ r |= if10 ((x .<<. (Int 24)) .>=. (y .<<. (Int 24)))+  Int8GtOp          -> \[r] [x,y] -> PrimInline $ r |= if10 ((x .<<. (Int 24)) .>.  (y .<<. (Int 24)))+  Int8LeOp          -> \[r] [x,y] -> PrimInline $ r |= if10 ((x .<<. (Int 24)) .<=. (y .<<. (Int 24)))+  Int8LtOp          -> \[r] [x,y] -> PrimInline $ r |= if10 ((x .<<. (Int 24)) .<.  (y .<<. (Int 24)))+  Int8NeOp          -> \[r] [x,y] -> PrimInline $ r |= if10 (x .!==. y)++  Int8SraOp         -> \[r] [x,i]   -> PrimInline $ r |= x .>>. i+  Int8SrlOp         -> \[r] [x,i]   -> PrimInline $ r |= signExtend8 (mask8 x .>>>. i)+  Int8SllOp         -> \[r] [x,i]   -> PrimInline $ r |= signExtend8 (mask8 (x .<<. i))++------------------------------ Word8 --------------------------------------------++  Word8ToWordOp      -> \[r] [x]       -> PrimInline $ r |= mask8 x+  WordToWord8Op      -> \[r] [x]       -> PrimInline $ r |= mask8 x++  Word8AddOp         -> \[r] [x,y]     -> PrimInline $ r |= mask8 (Add x y)+  Word8SubOp         -> \[r] [x,y]     -> PrimInline $ r |= mask8 (Sub x y)+  Word8MulOp         -> \[r] [x,y]     -> PrimInline $ r |= mask8 (Mul x y)+  Word8QuotOp        -> \[r] [x,y]     -> PrimInline $ r |= mask8 (Div x y)+  Word8RemOp         -> \[r] [x,y]     -> PrimInline $ r |= Mod x y+  Word8QuotRemOp     -> \[r1,r2] [x,y] -> PrimInline $ mconcat+                                                  [ r1 |= toI32 (Div x y)+                                                  , r2 |= Mod x y+                                                  ]+  Word8EqOp          -> \[r] [x,y] -> PrimInline $ r |= if10 (x .===. y)+  Word8GeOp          -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>=. y)+  Word8GtOp          -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>. y)+  Word8LeOp          -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<=. y)+  Word8LtOp          -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<. y)+  Word8NeOp          -> \[r] [x,y] -> PrimInline $ r |= if10 (x .!==. y)++  Word8AndOp         -> \[r] [x,y]   -> PrimInline $ r |= BAnd x y+  Word8OrOp          -> \[r] [x,y]   -> PrimInline $ r |= BOr  x y+  Word8XorOp         -> \[r] [x,y]   -> PrimInline $ r |= BXor x y+  Word8NotOp         -> \[r] [x]     -> PrimInline $ r |= BXor x (Int 0xff)++  Word8SllOp         -> \[r] [x,i]   -> PrimInline $ r |= mask8 (x .<<. i)+  Word8SrlOp         -> \[r] [x,i]   -> PrimInline $ r |= x .>>>. i++------------------------------ Int16 -------------------------------------------++  Int16ToIntOp       -> \[r] [x]       -> PrimInline $ r |= x+  IntToInt16Op       -> \[r] [x]       -> PrimInline $ r |= signExtend16 x++  Int16NegOp         -> \[r] [x]       -> PrimInline $ r |= signExtend16 (Negate x)+  Int16AddOp         -> \[r] [x,y]     -> PrimInline $ r |= signExtend16 (Add x y)+  Int16SubOp         -> \[r] [x,y]     -> PrimInline $ r |= signExtend16 (Sub x y)+  Int16MulOp         -> \[r] [x,y]     -> PrimInline $ r |= signExtend16 (Mul x y)+  Int16QuotOp        -> \[r] [x,y]     -> PrimInline $ r |= signExtend16 (quotShortInt 16 x y)+  Int16RemOp         -> \[r] [x,y]     -> PrimInline $ r |= signExtend16 (remShortInt 16 x y)+  Int16QuotRemOp     -> \[r1,r2] [x,y] -> PrimInline $ mconcat+                                                [ r1 |= signExtend16 (quotShortInt 16 x y)+                                                , r2 |= signExtend16 (remShortInt 16 x y)+                                                ]+  Int16EqOp          -> \[r] [x,y] -> PrimInline $ r |= if10 (x .===. y)+  Int16GeOp          -> \[r] [x,y] -> PrimInline $ r |= if10 ((x .<<. (Int 16)) .>=. (y .<<. (Int 16)))+  Int16GtOp          -> \[r] [x,y] -> PrimInline $ r |= if10 ((x .<<. (Int 16)) .>.  (y .<<. (Int 16)))+  Int16LeOp          -> \[r] [x,y] -> PrimInline $ r |= if10 ((x .<<. (Int 16)) .<=. (y .<<. (Int 16)))+  Int16LtOp          -> \[r] [x,y] -> PrimInline $ r |= if10 ((x .<<. (Int 16)) .<.  (y .<<. (Int 16)))+  Int16NeOp          -> \[r] [x,y] -> PrimInline $ r |= if10 (x .!==. y)++  Int16SraOp         -> \[r] [x,i]   -> PrimInline $ r |= x .>>. i+  Int16SrlOp         -> \[r] [x,i]   -> PrimInline $ r |= signExtend16 (mask16 x .>>>. i)+  Int16SllOp         -> \[r] [x,i]   -> PrimInline $ r |= signExtend16 (x .<<. i)++------------------------------ Word16 ------------------------------------------++  Word16ToWordOp     -> \[r] [x]   -> PrimInline $ r |= x+  WordToWord16Op     -> \[r] [x]   -> PrimInline $ r |= mask16 x++  Word16AddOp        -> \[r] [x,y] -> PrimInline $ r |= mask16 (Add x y)+  Word16SubOp        -> \[r] [x,y] -> PrimInline $ r |= mask16 (Sub x y)+  Word16MulOp        -> \[r] [x,y] -> PrimInline $ r |= mask16 (Mul x y)+  Word16QuotOp       -> \[r] [x,y] -> PrimInline $ r |= mask16 (Div x y)+  Word16RemOp        -> \[r] [x,y] -> PrimInline $ r |= Mod x y+  Word16QuotRemOp    -> \[r1,r2] [x,y] -> PrimInline $ mconcat+                                                [ r1 |= toI32 (Div x y)+                                                , r2 |= Mod x y+                                                ]+  Word16EqOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .===. y)+  Word16GeOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>=. y)+  Word16GtOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>. y)+  Word16LeOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<=. y)+  Word16LtOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<. y)+  Word16NeOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .!==. y)++  Word16AndOp        -> \[r] [x,y]   -> PrimInline $ r |= BAnd x y+  Word16OrOp         -> \[r] [x,y]   -> PrimInline $ r |= BOr  x y+  Word16XorOp        -> \[r] [x,y]   -> PrimInline $ r |= BXor x y+  Word16NotOp        -> \[r] [x]     -> PrimInline $ r |= BXor x (Int 0xffff)++  Word16SllOp        -> \[r] [x,i]   -> PrimInline $ r |= mask16 (x .<<. i)+  Word16SrlOp        -> \[r] [x,i]   -> PrimInline $ r |= x .>>>. i++------------------------------ Int32 --------------------------------------------++  Int32ToIntOp       -> \[r] [x]   -> PrimInline $ r |= x+  IntToInt32Op       -> \[r] [x]   -> PrimInline $ r |= x++  Int32NegOp         -> \rs  xs    -> genPrim prof bound ty IntNegOp rs xs+  Int32AddOp         -> \rs  xs    -> genPrim prof bound ty IntAddOp rs xs+  Int32SubOp         -> \rs  xs    -> genPrim prof bound ty IntSubOp rs xs+  Int32MulOp         -> \rs  xs    -> genPrim prof bound ty IntMulOp rs xs+  Int32QuotOp        -> \rs  xs    -> genPrim prof bound ty IntQuotOp rs xs+  Int32RemOp         -> \rs  xs    -> genPrim prof bound ty IntRemOp rs xs+  Int32QuotRemOp     -> \rs  xs    -> genPrim prof bound ty IntQuotRemOp rs xs++  Int32EqOp          -> \rs  xs    -> genPrim prof bound ty IntEqOp rs xs+  Int32GeOp          -> \rs  xs    -> genPrim prof bound ty IntGeOp rs xs+  Int32GtOp          -> \rs  xs    -> genPrim prof bound ty IntGtOp rs xs+  Int32LeOp          -> \rs  xs    -> genPrim prof bound ty IntLeOp rs xs+  Int32LtOp          -> \rs  xs    -> genPrim prof bound ty IntLtOp rs xs+  Int32NeOp          -> \rs  xs    -> genPrim prof bound ty IntNeOp rs xs++  Int32SraOp         -> \rs  xs    -> genPrim prof bound ty IntSraOp rs xs+  Int32SrlOp         -> \rs  xs    -> genPrim prof bound ty IntSrlOp rs xs+  Int32SllOp         -> \rs  xs    -> genPrim prof bound ty IntSllOp rs xs++------------------------------ Word32 -------------------------------------------++  Word32ToWordOp     -> \[r] [x]   -> PrimInline $ r |= x+  WordToWord32Op     -> \[r] [x]   -> PrimInline $ r |= x++  Word32AddOp        -> \rs  xs    -> genPrim prof bound ty WordAddOp rs xs+  Word32SubOp        -> \rs  xs    -> genPrim prof bound ty WordSubOp rs xs+  Word32MulOp        -> \rs  xs    -> genPrim prof bound ty WordMulOp rs xs+  Word32QuotOp       -> \rs  xs    -> genPrim prof bound ty WordQuotOp rs xs+  Word32RemOp        -> \rs  xs    -> genPrim prof bound ty WordRemOp rs xs+  Word32QuotRemOp    -> \rs  xs    -> genPrim prof bound ty WordQuotRemOp rs xs++  Word32EqOp         -> \rs  xs    -> genPrim prof bound ty WordEqOp rs xs+  Word32GeOp         -> \rs  xs    -> genPrim prof bound ty WordGeOp rs xs+  Word32GtOp         -> \rs  xs    -> genPrim prof bound ty WordGtOp rs xs+  Word32LeOp         -> \rs  xs    -> genPrim prof bound ty WordLeOp rs xs+  Word32LtOp         -> \rs  xs    -> genPrim prof bound ty WordLtOp rs xs+  Word32NeOp         -> \rs  xs    -> genPrim prof bound ty WordNeOp rs xs++  Word32AndOp        -> \rs xs     -> genPrim prof bound ty WordAndOp rs xs+  Word32OrOp         -> \rs xs     -> genPrim prof bound ty WordOrOp rs xs+  Word32XorOp        -> \rs xs     -> genPrim prof bound ty WordXorOp rs xs+  Word32NotOp        -> \rs xs     -> genPrim prof bound ty WordNotOp rs xs++  Word32SllOp        -> \rs xs     -> genPrim prof bound ty WordSllOp rs xs+  Word32SrlOp        -> \rs xs     -> genPrim prof bound ty WordSrlOp rs xs++------------------------------ Int64 --------------------------------------------++  Int64ToIntOp      -> \[r] [_h,l] -> PrimInline $ r |= toI32 l++  Int64NegOp        -> \[r_h,r_l] [h,l] ->+      PrimInline $ mconcat+        [ r_l |= toU32 (BNot l + 1)+        , r_h |= toI32 (BNot h + Not r_l)+        ]++  Int64AddOp  -> \[hr,lr] [h0,l0,h1,l1] -> PrimInline $ appT [hr,lr] "h$hs_plusInt64"  [h0,l0,h1,l1]+  Int64SubOp  -> \[hr,lr] [h0,l0,h1,l1] -> PrimInline $ appT [hr,lr] "h$hs_minusInt64" [h0,l0,h1,l1]+  Int64MulOp  -> \[hr,lr] [h0,l0,h1,l1] -> PrimInline $ appT [hr,lr] "h$hs_timesInt64" [h0,l0,h1,l1]+  Int64QuotOp -> \[hr,lr] [h0,l0,h1,l1] -> PrimInline $ appT [hr,lr] "h$hs_quotInt64"  [h0,l0,h1,l1]+  Int64RemOp  -> \[hr,lr] [h0,l0,h1,l1] -> PrimInline $ appT [hr,lr] "h$hs_remInt64"   [h0,l0,h1,l1]++  Int64SllOp  -> \[hr,lr] [h,l,n] -> PrimInline $ appT [hr,lr] "h$hs_uncheckedShiftLLInt64" [h,l,n]+  Int64SraOp  -> \[hr,lr] [h,l,n] -> PrimInline $ appT [hr,lr] "h$hs_uncheckedShiftRAInt64" [h,l,n]+  Int64SrlOp  -> \[hr,lr] [h,l,n] -> PrimInline $ appT [hr,lr] "h$hs_uncheckedShiftRLInt64" [h,l,n]++  Int64ToWord64Op   -> \[r1,r2] [x1,x2] ->+      PrimInline $ mconcat+       [ r1 |= toU32 x1+       , r2 |= x2+       ]+  IntToInt64Op      -> \[r1,r2] [x] ->+      PrimInline $ mconcat+       [ r1 |= if_ (x .<. 0) (-1) 0 -- sign-extension+       , r2 |= toU32 x+       ]++  Int64EqOp -> \[r] [h0,l0,h1,l1] -> PrimInline $ r |= if10 (LAnd (l0 .===. l1) (h0 .===. h1))+  Int64NeOp -> \[r] [h0,l0,h1,l1] -> PrimInline $ r |= if10 (LOr (l0 .!==. l1) (h0 .!==. h1))+  Int64GeOp -> \[r] [h0,l0,h1,l1] -> PrimInline $ r |= if10 (LOr (h0 .>. h1) (LAnd (h0 .===. h1) (l0 .>=. l1)))+  Int64GtOp -> \[r] [h0,l0,h1,l1] -> PrimInline $ r |= if10 (LOr (h0 .>. h1) (LAnd (h0 .===. h1) (l0 .>. l1)))+  Int64LeOp -> \[r] [h0,l0,h1,l1] -> PrimInline $ r |= if10 (LOr (h0 .<. h1) (LAnd (h0 .===. h1) (l0 .<=. l1)))+  Int64LtOp -> \[r] [h0,l0,h1,l1] -> PrimInline $ r |= if10 (LOr (h0 .<. h1) (LAnd (h0 .===. h1) (l0 .<. l1)))++------------------------------ Word64 -------------------------------------------++  Word64ToWordOp    -> \[r] [_x1,x2] -> PrimInline $ r |= x2++  WordToWord64Op    -> \[rh,rl] [x] ->+    PrimInline $ mconcat+     [ rh |= 0+     , rl |= x+     ]++  Word64ToInt64Op   -> \[r1,r2] [x1,x2] ->+    PrimInline $ mconcat+     [ r1 |= toI32 x1+     , r2 |= x2+     ]++  Word64EqOp -> \[r] [h0,l0,h1,l1] -> PrimInline $ r |= if10 (LAnd (l0 .===. l1) (h0 .===. h1))+  Word64NeOp -> \[r] [h0,l0,h1,l1] -> PrimInline $ r |= if10 (LOr (l0 .!==. l1) (h0 .!==. h1))+  Word64GeOp -> \[r] [h0,l0,h1,l1] -> PrimInline $ r |= if10 (LOr (h0 .>. h1) (LAnd (h0 .===. h1) (l0 .>=. l1)))+  Word64GtOp -> \[r] [h0,l0,h1,l1] -> PrimInline $ r |= if10 (LOr (h0 .>. h1) (LAnd (h0 .===. h1) (l0 .>. l1)))+  Word64LeOp -> \[r] [h0,l0,h1,l1] -> PrimInline $ r |= if10 (LOr (h0 .<. h1) (LAnd (h0 .===. h1) (l0 .<=. l1)))+  Word64LtOp -> \[r] [h0,l0,h1,l1] -> PrimInline $ r |= if10 (LOr (h0 .<. h1) (LAnd (h0 .===. h1) (l0 .<. l1)))++  Word64SllOp -> \[hr,lr] [h,l,n] -> PrimInline $ appT [hr,lr] "h$hs_uncheckedShiftLWord64" [h,l,n]+  Word64SrlOp -> \[hr,lr] [h,l,n] -> PrimInline $ appT [hr,lr] "h$hs_uncheckedShiftRWord64" [h,l,n]++  Word64OrOp  -> \[hr,hl] [h0, l0, h1, l1] ->+      PrimInline $ mconcat+        [ hr |= toU32 (BOr h0 h1)+        , hl |= toU32 (BOr l0 l1)+        ]++  Word64AndOp -> \[hr,hl] [h0, l0, h1, l1] ->+      PrimInline $ mconcat+        [ hr |= toU32 (BAnd h0 h1)+        , hl |= toU32 (BAnd l0 l1)+        ]++  Word64XorOp -> \[hr,hl] [h0, l0, h1, l1] ->+      PrimInline $ mconcat+        [ hr |= toU32 (BXor h0 h1)+        , hl |= toU32 (BXor l0 l1)+        ]++  Word64NotOp -> \[hr,hl] [h, l] ->+      PrimInline $ mconcat+        [ hr |= toU32 (BNot h)+        , hl |= toU32 (BNot l)+        ]++  Word64AddOp  -> \[hr,lr] [h0,l0,h1,l1] -> PrimInline $ appT [hr,lr] "h$hs_plusWord64"  [h0,l0,h1,l1]+  Word64SubOp  -> \[hr,lr] [h0,l0,h1,l1] -> PrimInline $ appT [hr,lr] "h$hs_minusWord64" [h0,l0,h1,l1]+  Word64MulOp  -> \[hr,lr] [h0,l0,h1,l1] -> PrimInline $ appT [hr,lr] "h$hs_timesWord64" [h0,l0,h1,l1]+  Word64QuotOp -> \[hr,lr] [h0,l0,h1,l1] -> PrimInline $ appT [hr,lr] "h$hs_quotWord64"  [h0,l0,h1,l1]+  Word64RemOp  -> \[hr,lr] [h0,l0,h1,l1] -> PrimInline $ appT [hr,lr] "h$hs_remWord64"   [h0,l0,h1,l1]++------------------------------ Word ---------------------------------------------++  WordAddOp  -> \[r]   [x,y] -> PrimInline $ r |= (x `Add` y) .>>>. zero_+  WordAddCOp -> \[r,c] [x,y] -> PrimInline $+      jVar \t -> mconcat+        [ t |= x `Add` y+        , r |= toU32 t+        , c |= if10 (t .!==. r)+        ]+  WordSubCOp  -> \[r,c] [x,y] ->+      PrimInline $ mconcat+        [ r |= toU32 (Sub x y)+        , c |= if10 (y .>. x)+        ]+  WordAdd2Op    -> \[h,l] [x,y] -> PrimInline $ appT [h,l] "h$wordAdd2" [x,y]+  WordSubOp     -> \  [r] [x,y] -> PrimInline $ r |= toU32 (Sub x y)+  WordMulOp     -> \  [r] [x,y] -> PrimInline $ r |= app "h$mulWord32" [x, y]+  WordMul2Op    -> \[h,l] [x,y] -> PrimInline $ appT [h,l] "h$mul2Word32" [x,y]+  WordQuotOp    -> \  [q] [x,y] -> PrimInline $ q |= app "h$quotWord32" [x,y]+  WordRemOp     -> \  [r] [x,y] -> PrimInline $ r |= app "h$remWord32" [x,y]+  WordQuotRemOp -> \[q,r] [x,y] -> PrimInline $ appT [q,r] "h$quotRemWord32" [x,y]+  WordQuotRem2Op   -> \[q,r] [xh,xl,y] -> PrimInline $ appT [q,r] "h$quotRem2Word32" [xh,xl,y]+  WordAndOp        -> \[r] [x,y] -> PrimInline $ r |= toU32 (BAnd x y)+  WordOrOp         -> \[r] [x,y] -> PrimInline $ r |= toU32 (BOr  x y)+  WordXorOp        -> \[r] [x,y] -> PrimInline $ r |= toU32 (BXor x y)+  WordNotOp        -> \[r] [x]   -> PrimInline $ r |= toU32 (BNot x)+  WordSllOp        -> \[r] [x,y] -> PrimInline $ r |= toU32 (x .<<. y)+  WordSrlOp        -> \[r] [x,y] -> PrimInline $ r |= x .>>>. y+  WordToIntOp      -> \[r] [x]   -> PrimInline $ r |= toI32 x+  WordGtOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>.  y)+  WordGeOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>=. y)+  WordEqOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .===. y)+  WordNeOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .!==. y)+  WordLtOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<.  y)+  WordLeOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<=. y)+  WordToDoubleOp   -> \[r] [x]   -> PrimInline $ r |= x+  WordToFloatOp    -> \[r] [x]   -> PrimInline $ r |= math_fround [x]+  PopCnt8Op        -> \[r] [x]   -> PrimInline $ r |= var "h$popCntTab" .! (mask8 x)+  PopCnt16Op       -> \[r] [x]   -> PrimInline $ r |= Add (var "h$popCntTab" .! (mask8 x))+                                                      (var "h$popCntTab" .! (mask8 (x .>>>. Int 8)))++  PopCnt32Op  -> \[r] [x]     -> PrimInline $ r |= app "h$popCnt32" [x]+  PopCnt64Op  -> \[r] [x1,x2] -> PrimInline $ r |= app "h$popCnt64" [x1,x2]+  PopCntOp    -> \[r] [x]     -> genPrim prof bound ty PopCnt32Op [r] [x]+  Pdep8Op     -> \[r] [s,m]   -> PrimInline $ r |= app "h$pdep8"  [s,m]+  Pdep16Op    -> \[r] [s,m]   -> PrimInline $ r |= app "h$pdep16" [s,m]+  Pdep32Op    -> \[r] [s,m]   -> PrimInline $ r |= app "h$pdep32" [s,m]+  Pdep64Op    -> \[ra,rb] [sa,sb,ma,mb] -> PrimInline $ appT [ra,rb] "h$pdep64" [sa,sb,ma,mb]+  PdepOp      -> \rs xs                 -> genPrim prof bound ty Pdep32Op rs xs+  Pext8Op     -> \[r] [s,m] -> PrimInline $ r |= app "h$pext8" [s,m]+  Pext16Op    -> \[r] [s,m] -> PrimInline $ r |= app "h$pext16" [s,m]+  Pext32Op    -> \[r] [s,m] -> PrimInline $ r |= app "h$pext32" [s,m]+  Pext64Op    -> \[ra,rb] [sa,sb,ma,mb] -> PrimInline $ appT [ra,rb] "h$pext64" [sa,sb,ma,mb]+  PextOp      -> \rs xs     -> genPrim prof bound ty Pext32Op rs xs++  ClzOp       -> \[r]   [x]     -> PrimInline $ r |= app "h$clz32" [x]+  Clz8Op      -> \[r]   [x]     -> PrimInline $ r |= app "h$clz8"  [x]+  Clz16Op     -> \[r]   [x]     -> PrimInline $ r |= app "h$clz16" [x]+  Clz32Op     -> \[r]   [x]     -> PrimInline $ r |= app "h$clz32" [x]+  Clz64Op     -> \[r]   [x1,x2] -> PrimInline $ r |= app "h$clz64" [x1,x2]+  CtzOp       -> \[r]   [x]     -> PrimInline $ r |= app "h$ctz32" [x]+  Ctz8Op      -> \[r]   [x]     -> PrimInline $ r |= app "h$ctz8"  [x]+  Ctz16Op     -> \[r]   [x]     -> PrimInline $ r |= app "h$ctz16" [x]+  Ctz32Op     -> \[r]   [x]     -> PrimInline $ r |= app "h$ctz32" [x]+  Ctz64Op     -> \[r]   [x1,x2] -> PrimInline $ r |= app "h$ctz64" [x1,x2]++  BSwap16Op   -> \[r] [x]   -> PrimInline $+      r |= BOr ((mask8 x) .<<. (Int 8))+               (mask8 (x .>>>. (Int 8)))+  BSwap32Op   -> \[r] [x]   -> PrimInline $+      r |= toU32 ((x .<<. (Int 24))+            `BOr` ((BAnd x (Int 0xFF00)) .<<. (Int 8))+            `BOr` ((BAnd x (Int 0xFF0000)) .>>. (Int 8))+            `BOr` (x .>>>. (Int 24)))+  BSwap64Op   -> \[r1,r2] [x,y] -> PrimInline $ appT [r1,r2] "h$bswap64" [x,y]+  BSwapOp     -> \[r] [x]       -> genPrim prof bound ty BSwap32Op [r] [x]++  BRevOp      -> \[r] [w] -> genPrim prof bound ty BRev32Op [r] [w]+  BRev8Op     -> \[r] [w] -> PrimInline $ r |= (app "h$reverseWord" [w] .>>>. 24)+  BRev16Op    -> \[r] [w] -> PrimInline $ r |= (app "h$reverseWord" [w] .>>>. 16)+  BRev32Op    -> \[r] [w] -> PrimInline $ r |= app "h$reverseWord" [w]+  BRev64Op    -> \[rh,rl] [h,l] -> PrimInline $ mconcat [ rl |= app "h$reverseWord" [h]+                                                        , rh |= app "h$reverseWord" [l]+                                                        ]++------------------------------ Narrow -------------------------------------------++  Narrow8IntOp    -> \[r] [x] -> PrimInline $ r |= signExtend8  x+  Narrow16IntOp   -> \[r] [x] -> PrimInline $ r |= signExtend16 x+  Narrow32IntOp   -> \[r] [x] -> PrimInline $ r |= toI32  x+  Narrow8WordOp   -> \[r] [x] -> PrimInline $ r |= mask8  x+  Narrow16WordOp  -> \[r] [x] -> PrimInline $ r |= mask16 x+  Narrow32WordOp  -> \[r] [x] -> PrimInline $ r |= toU32  x++------------------------------ Double -------------------------------------------++  DoubleGtOp        -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>.   y)+  DoubleGeOp        -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>=.  y)+  DoubleEqOp        -> \[r] [x,y] -> PrimInline $ r |= if10 (x .===. y)+  DoubleNeOp        -> \[r] [x,y] -> PrimInline $ r |= if10 (x .!==. y)+  DoubleLtOp        -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<.   y)+  DoubleLeOp        -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<=.  y)+  DoubleAddOp       -> \[r] [x,y] -> PrimInline $ r |= Add x y+  DoubleSubOp       -> \[r] [x,y] -> PrimInline $ r |= Sub x y+  DoubleMulOp       -> \[r] [x,y] -> PrimInline $ r |= Mul x y+  DoubleDivOp       -> \[r] [x,y] -> PrimInline $ r |= Div x y+  DoubleNegOp       -> \[r] [x]   -> PrimInline $ r |= Negate x+  DoubleFabsOp      -> \[r] [x]   -> PrimInline $ r |= math_abs [x]+  DoubleToIntOp     -> \[r] [x]   -> PrimInline $ r |= toI32 x+  DoubleToFloatOp   -> \[r] [x]   -> PrimInline $ r |= math_fround [x]+  DoubleExpOp       -> \[r] [x]   -> PrimInline $ r |= math_exp  [x]+  DoubleExpM1Op     -> \[r] [x]   -> PrimInline $ r |= math_expm1 [x]+  DoubleLogOp       -> \[r] [x]   -> PrimInline $ r |= math_log  [x]+  DoubleLog1POp     -> \[r] [x]   -> PrimInline $ r |= math_log1p [x]+  DoubleSqrtOp      -> \[r] [x]   -> PrimInline $ r |= math_sqrt [x]+  DoubleSinOp       -> \[r] [x]   -> PrimInline $ r |= math_sin  [x]+  DoubleCosOp       -> \[r] [x]   -> PrimInline $ r |= math_cos  [x]+  DoubleTanOp       -> \[r] [x]   -> PrimInline $ r |= math_tan  [x]+  DoubleAsinOp      -> \[r] [x]   -> PrimInline $ r |= math_asin [x]+  DoubleAcosOp      -> \[r] [x]   -> PrimInline $ r |= math_acos [x]+  DoubleAtanOp      -> \[r] [x]   -> PrimInline $ r |= math_atan [x]+  DoubleSinhOp      -> \[r] [x]   -> PrimInline $ r |= math_sinh [x]+  DoubleCoshOp      -> \[r] [x]   -> PrimInline $ r |= math_cosh [x]+  DoubleTanhOp      -> \[r] [x]   -> PrimInline $ r |= math_tanh [x]+  DoubleAsinhOp     -> \[r] [x]   -> PrimInline $ r |= math_asinh [x]+  DoubleAcoshOp     -> \[r] [x]   -> PrimInline $ r |= math_acosh [x]+  DoubleAtanhOp     -> \[r] [x]   -> PrimInline $ r |= math_atanh [x]+  DoublePowerOp     -> \[r] [x,y] -> PrimInline $ r |= math_pow [x,y]+  DoubleDecode_2IntOp  -> \[s,h,l,e] [x] -> PrimInline $ appT [s,h,l,e] "h$decodeDouble2Int" [x]+  DoubleDecode_Int64Op -> \[s1,s2,e] [d] -> PrimInline $ appT [e,s1,s2] "h$decodeDoubleInt64" [d]++------------------------------ Float --------------------------------------------++  FloatGtOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>.   y)+  FloatGeOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .>=.  y)+  FloatEqOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .===. y)+  FloatNeOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .!==. y)+  FloatLtOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<.   y)+  FloatLeOp         -> \[r] [x,y] -> PrimInline $ r |= if10 (x .<=.  y)+  FloatAddOp        -> \[r] [x,y] -> PrimInline $ r |= math_fround [Add x y]+  FloatSubOp        -> \[r] [x,y] -> PrimInline $ r |= math_fround [Sub x y]+  FloatMulOp        -> \[r] [x,y] -> PrimInline $ r |= math_fround [Mul x y]+  FloatDivOp        -> \[r] [x,y] -> PrimInline $ r |= math_fround [Div x y]+  FloatNegOp        -> \[r] [x]   -> PrimInline $ r |= Negate x+  FloatFabsOp       -> \[r] [x]   -> PrimInline $ r |= math_abs [x]+  FloatToIntOp      -> \[r] [x]   -> PrimInline $ r |= toI32 x+  FloatExpOp        -> \[r] [x]   -> PrimInline $ r |= math_fround [math_exp [x]]+  FloatExpM1Op      -> \[r] [x]   -> PrimInline $ r |= math_fround [math_expm1 [x]]+  FloatLogOp        -> \[r] [x]   -> PrimInline $ r |= math_fround [math_log [x]]+  FloatLog1POp      -> \[r] [x]   -> PrimInline $ r |= math_fround [math_log1p [x]]+  FloatSqrtOp       -> \[r] [x]   -> PrimInline $ r |= math_fround [math_sqrt [x]]+  FloatSinOp        -> \[r] [x]   -> PrimInline $ r |= math_fround [math_sin [x]]+  FloatCosOp        -> \[r] [x]   -> PrimInline $ r |= math_fround [math_cos [x]]+  FloatTanOp        -> \[r] [x]   -> PrimInline $ r |= math_fround [math_tan [x]]+  FloatAsinOp       -> \[r] [x]   -> PrimInline $ r |= math_fround [math_asin [x]]+  FloatAcosOp       -> \[r] [x]   -> PrimInline $ r |= math_fround [math_acos [x]]+  FloatAtanOp       -> \[r] [x]   -> PrimInline $ r |= math_fround [math_atan [x]]+  FloatSinhOp       -> \[r] [x]   -> PrimInline $ r |= math_fround [math_sinh [x]]+  FloatCoshOp       -> \[r] [x]   -> PrimInline $ r |= math_fround [math_cosh [x]]+  FloatTanhOp       -> \[r] [x]   -> PrimInline $ r |= math_fround [math_tanh [x]]+  FloatAsinhOp      -> \[r] [x]   -> PrimInline $ r |= math_fround [math_asinh [x]]+  FloatAcoshOp      -> \[r] [x]   -> PrimInline $ r |= math_fround [math_acosh [x]]+  FloatAtanhOp      -> \[r] [x]   -> PrimInline $ r |= math_fround [math_atanh [x]]+  FloatPowerOp      -> \[r] [x,y] -> PrimInline $ r |= math_fround [math_pow [x,y]]+  FloatToDoubleOp   -> \[r] [x]   -> PrimInline $ r |= x+  FloatDecode_IntOp -> \[s,e] [x] -> PrimInline $ appT [s,e] "h$decodeFloatInt" [x]++------------------------------ Arrays -------------------------------------------++  NewArrayOp           -> \[r] [l,e]   -> PrimInline (newArray r l e)+  ReadArrayOp          -> \[r] [a,i]   -> PrimInline $ boundsChecked bound a i (r |= a .! i)+  WriteArrayOp         -> \[]  [a,i,v] -> PrimInline $ boundsChecked bound a i (a .! i |= v)+  SizeofArrayOp        -> \[r] [a]     -> PrimInline $ r |= a .^ "length"+  SizeofMutableArrayOp -> \[r] [a]     -> PrimInline $ r |= a .^ "length"+  IndexArrayOp         -> \[r] [a,i]   -> PrimInline $ boundsChecked bound a i (r |= a .! i)+  UnsafeFreezeArrayOp  -> \[r] [a]     -> PrimInline $ r |= a+  UnsafeThawArrayOp    -> \[r] [a]     -> PrimInline $ r |= a+  CopyArrayOp          -> \[] [a,o1,ma,o2,n] ->+      PrimInline $ loopBlockS (Int 0) (.<. n) \i ->+        [ ma .! (Add i o2) |= a .! (Add i o1)+        , preIncrS i+        ]+  CopyMutableArrayOp  -> \[]  [a1,o1,a2,o2,n] -> PrimInline $ appS "h$copyMutableArray" [a1,o1,a2,o2,n]+  CloneArrayOp        -> \[r] [a,start,n]     -> PrimInline $ r |= app "h$sliceArray" [a,start,n]+  CloneMutableArrayOp -> \[r] [a,start,n]     -> genPrim prof bound ty CloneArrayOp [r] [a,start,n]+  FreezeArrayOp       -> \[r] [a,start,n]     -> PrimInline $ r |= app "h$sliceArray" [a,start,n]+  ThawArrayOp         -> \[r] [a,start,n]     -> PrimInline $ r |= app "h$sliceArray" [a,start,n]+  CasArrayOp          -> \[s,o] [a,i,old,new] -> PrimInline $+      jVar \x -> mconcat+        [ x |= a .! i+        , ifBlockS (x .===. old)+                   [ o |= new+                   , a .! i |= new+                   , s |= zero_+                   ]+                   [ s |= one_+                   , o |= x+                   ]+        ]++------------------------------ Small Arrays -------------------------------------++  NewSmallArrayOp            -> \[a]   [n,e]         -> PrimInline $ a |= app "h$newArray" [n,e]+  ReadSmallArrayOp           -> \[r]   [a,i]         -> PrimInline $ boundsChecked bound a i (r |= a .! i)+  WriteSmallArrayOp          -> \[]    [a,i,e]       -> PrimInline $ boundsChecked bound a i (a .! i |= e)+  SizeofSmallArrayOp         -> \[r]   [a]           -> PrimInline $ r |= a .^ "length"+  SizeofSmallMutableArrayOp  -> \[r]   [a]           -> PrimInline $ r |= a .^ "length"+  IndexSmallArrayOp          -> \[r]   [a,i]         -> PrimInline $ boundsChecked bound a i (r |= a .! i)+  UnsafeFreezeSmallArrayOp   -> \[r]   [a]           -> PrimInline $ r |= a+  UnsafeThawSmallArrayOp     -> \[r]   [a]           -> PrimInline $ r |= a+  CopySmallArrayOp           -> \[]    [s,si,d,di,n] -> PrimInline $+      loopBlockS (Sub n one_) (.>=. zero_) \i ->+        [ d .! (Add di i) |= s .! (Add si i)+        , postDecrS i+        ]+  CopySmallMutableArrayOp    -> \[]    [s,si,d,di,n] -> PrimInline $+      loopBlockS (Sub n one_) (.>=. zero_) \i ->+        [ d .! (Add di i) |= s .! (Add si i)+        , postDecrS i+        ]+  CloneSmallArrayOp          -> \[r]   [a,o,n]       -> PrimInline $ cloneArray r a (Just o) n+  CloneSmallMutableArrayOp   -> \[r]   [a,o,n]       -> PrimInline $ cloneArray r a (Just o) n+  FreezeSmallArrayOp         -> \[r]   [a,o,n]       -> PrimInline $ cloneArray r a (Just o) n+  ThawSmallArrayOp           -> \[r]   [a,o,n]       -> PrimInline $ cloneArray r a (Just o) n+  CasSmallArrayOp            -> \[s,o] [a,i,old,new] -> PrimInline $ jVar \x -> mconcat+                                                                [ x |= a .! i+                                                                , ifBlockS (x .===. old)+                                                                    [ o |= new+                                                                    , a .! i |= new+                                                                    , s |= zero_+                                                                    ]+                                                                    [ s |= one_+                                                                    , o |= x+                                                                    ]+                                                                ]++------------------------------- Byte Arrays -------------------------------------++  NewByteArrayOp_Char               -> \[r] [l]         -> PrimInline (newByteArray r l)+  NewPinnedByteArrayOp_Char         -> \[r] [l]         -> PrimInline (newByteArray r l)+  NewAlignedPinnedByteArrayOp_Char  -> \[r] [l,_align]  -> PrimInline (newByteArray r l)+  MutableByteArrayIsPinnedOp        -> \[r] [_]         -> PrimInline $ r |= one_+  ByteArrayIsPinnedOp               -> \[r] [_]         -> PrimInline $ r |= one_+  ByteArrayContents_Char            -> \[a,o] [b]       -> PrimInline $ mconcat [a |= b, o |= zero_]+  MutableByteArrayContents_Char     -> \[a,o] [b]       -> PrimInline $ mconcat [a |= b, o |= zero_]+  ShrinkMutableByteArrayOp_Char     -> \[] [a,n]        -> PrimInline $ appS "h$shrinkMutableByteArray" [a,n]+  ResizeMutableByteArrayOp_Char     -> \[r] [a,n]       -> PrimInline $ r |= app "h$resizeMutableByteArray" [a,n]+  UnsafeFreezeByteArrayOp           -> \[a] [b]         -> PrimInline $ a |= b+  SizeofByteArrayOp                 -> \[r] [a]         -> PrimInline $ r |= a .^ "len"+  SizeofMutableByteArrayOp          -> \[r] [a]         -> PrimInline $ r |= a .^ "len"+  GetSizeofMutableByteArrayOp       -> \[r] [a]         -> PrimInline $ r |= a .^ "len"+  IndexByteArrayOp_Char             -> \[r] [a,i]       -> PrimInline . boundsChecked bound a i         $ r |= read_u8  a i+  IndexByteArrayOp_WideChar         -> \[r] [a,i]       -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_i32 a i+  IndexByteArrayOp_Int              -> \[r] [a,i]       -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_i32 a i+  IndexByteArrayOp_Word             -> \[r] [a,i]       -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_u32 a i+  IndexByteArrayOp_Addr             -> \[r1,r2] [a,i]   ->+    PrimInline . boundsChecked bound a i $ jVar \t -> mconcat+      [ t |= a .^ "arr"+      , ifBlockS (t .&&. t .! (i .<<. two_))+          [ r1 |= t .! (i .<<. two_) .! zero_+          , r2 |= t .! (i .<<. two_) .! one_+          ]+          [ r1 |= null_+          , r2 |= zero_+          ]+      ]++  IndexByteArrayOp_Float     -> \[r]     [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_f32 a i+  IndexByteArrayOp_Double    -> \[r]     [a,i] -> PrimInline . boundsChecked bound a (Add i 7) $ r |= read_f64 a i+  IndexByteArrayOp_StablePtr -> \[r1,r2] [a,i] ->+    PrimInline . boundsChecked bound a (Add i 3) $ mconcat+      [ r1 |= var "h$stablePtrBuf"+      , r2 |= read_i32 a i+      ]+  IndexByteArrayOp_Int8  -> \[r] [a,i]      -> PrimInline . boundsChecked bound a i         $ r |= read_i8  a i+  IndexByteArrayOp_Int16 -> \[r] [a,i]      -> PrimInline . boundsChecked bound a (Add i 1) $ r |= read_i16 a i+  IndexByteArrayOp_Int32 -> \[r] [a,i]      -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_i32 a i+  IndexByteArrayOp_Int64 -> \[h,l] [a,i]    -> PrimInline . boundsChecked bound a (Add i 7) $ mconcat+                                                     [ h |= read_i32 a (Add (i .<<. one_) one_)+                                                     , l |= read_u32 a (i .<<. one_)+                                                     ]+  IndexByteArrayOp_Word8  -> \[r] [a,i]     -> PrimInline . boundsChecked bound a i         $ r |= read_u8  a i+  IndexByteArrayOp_Word16 -> \[r] [a,i]     -> PrimInline . boundsChecked bound a (Add i 1) $ r |= read_u16 a i+  IndexByteArrayOp_Word32 -> \[r] [a,i]     -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_u32 a i+  IndexByteArrayOp_Word64 -> \[h,l] [a,i] -> PrimInline . boundsChecked bound a (Add i 7) $ mconcat+                                                      [ h |= read_u32 a (Add (i .<<. one_) one_)+                                                      , l |= read_u32 a (i .<<. one_)+                                                      ]+  ReadByteArrayOp_Char     -> \[r]     [a,i] -> PrimInline . boundsChecked bound a i         $ r |= read_u8  a i+  ReadByteArrayOp_WideChar -> \[r]     [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_i32 a i+  ReadByteArrayOp_Int      -> \[r]     [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_i32 a i+  ReadByteArrayOp_Word     -> \[r]     [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_u32 a i+  ReadByteArrayOp_Addr     -> \[r1,r2] [a,i] ->+      PrimInline $ jVar \x -> mconcat+        [ x |= i .<<. two_+        , ifS (a .^ "arr" .&&. a .^ "arr" .! x)+               (mconcat [ r1 |= a .^ "arr" .! x .! zero_+                        , r2 |= a .^ "arr" .! x .! one_+                        ])+               (mconcat [r1 |= null_, r2 |= one_])+        ]+  ReadByteArrayOp_Float     -> \[r]     [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_f32 a i+  ReadByteArrayOp_Double    -> \[r]     [a,i] -> PrimInline . boundsChecked bound a (Add i 7) $ r |= read_f64 a i+  ReadByteArrayOp_StablePtr -> \[r1,r2] [a,i] ->+      PrimInline . boundsChecked bound a (Add i 3) $ mconcat+       [ r1 |= var "h$stablePtrBuf"+       , r2 |= read_i32 a i+       ]+  ReadByteArrayOp_Int8  -> \[r]     [a,i] -> PrimInline . boundsChecked bound a i         $ r |= read_i8  a i+  ReadByteArrayOp_Int16 -> \[r]     [a,i] -> PrimInline . boundsChecked bound a (Add i 1) $ r |= read_i16 a i+  ReadByteArrayOp_Int32 -> \[r]     [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_i32 a i+  ReadByteArrayOp_Int64 -> \[h,l]   [a,i] ->+      PrimInline . boundsChecked bound a (Add i 7) $ mconcat+        [ h |= read_i32 a (Add (i .<<. one_) one_)+        , l |= read_u32 a (i .<<. one_)+        ]+  ReadByteArrayOp_Word8  -> \[r]     [a,i] -> PrimInline . boundsChecked bound a i         $ r |= read_u8  a i+  ReadByteArrayOp_Word16 -> \[r]     [a,i] -> PrimInline . boundsChecked bound a (Add i 1) $ r |= read_u16 a i+  ReadByteArrayOp_Word32 -> \[r]     [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_u32 a i+  ReadByteArrayOp_Word64 -> \[h,l]   [a,i] ->+      PrimInline . boundsChecked bound a (Add i 7) $ mconcat+        [ h |= read_u32 a (Add (i .<<. one_) one_)+        , l |= read_u32 a (i .<<. one_)+        ]+  WriteByteArrayOp_Char     -> \[] [a,i,e]     -> PrimInline . boundsChecked bound a i         $ write_u8  a i e+  WriteByteArrayOp_WideChar -> \[] [a,i,e]     -> PrimInline . boundsChecked bound a (Add i 3) $ write_i32 a i e+  WriteByteArrayOp_Int      -> \[] [a,i,e]     -> PrimInline . boundsChecked bound a (Add i 3) $ write_i32 a i e+  WriteByteArrayOp_Word     -> \[] [a,i,e]     -> PrimInline . boundsChecked bound a (Add i 3) $ write_u32 a i e+  WriteByteArrayOp_Addr     -> \[] [a,i,e1,e2] ->+    PrimInline $ mconcat+      [ ifS (Not (a .^ "arr")) (a .^ "arr" |= ValExpr (JList [])) mempty+      , a .^ "arr" .! (i .<<. two_) |= ValExpr (JList [e1, e2])+      ]+  WriteByteArrayOp_Float     -> \[] [a,i,e]      -> PrimInline . boundsChecked bound a (Add i 3) $ write_f32 a i e+  WriteByteArrayOp_Double    -> \[] [a,i,e]      -> PrimInline . boundsChecked bound a (Add i 7) $ write_f64 a i e+  WriteByteArrayOp_StablePtr -> \[] [a,i,_e1,e2] -> PrimInline . boundsChecked bound a (Add i 3) $ write_i32 a i e2++  WriteByteArrayOp_Int8  -> \[] [a,i,e]     -> PrimInline . boundsChecked bound a i         $ write_i8  a i e+  WriteByteArrayOp_Int16 -> \[] [a,i,e]     -> PrimInline . boundsChecked bound a (Add i 1) $ write_i16 a i e+  WriteByteArrayOp_Int32 -> \[] [a,i,e]     -> PrimInline . boundsChecked bound a (Add i 3) $ write_i32 a i e+  WriteByteArrayOp_Int64 -> \[] [a,i,e1,e2] ->+      PrimInline . boundsChecked bound a (Add i 7) $ mconcat+        [ write_i32 a (Add (i .<<. one_) one_) e1+        , write_u32 a (i .<<. one_)            e2+        ]+  WriteByteArrayOp_Word8  -> \[] [a,i,e]     -> PrimInline . boundsChecked bound a i         $ write_u8  a i e+  WriteByteArrayOp_Word16 -> \[] [a,i,e]     -> PrimInline . boundsChecked bound a (Add i 1) $ write_u16 a i e+  WriteByteArrayOp_Word32 -> \[] [a,i,e]     -> PrimInline . boundsChecked bound a (Add i 3) $ write_u32 a i e+  WriteByteArrayOp_Word64 -> \[] [a,i,h,l] ->+      PrimInline . boundsChecked bound a (Add i 7) $ mconcat+        [ write_u32 a (Add (i .<<. one_) one_) h+        , write_u32 a (i .<<. one_)            l+        ]+  CompareByteArraysOp -> \[r] [a1,o1,a2,o2,n] ->+      PrimInline . boundsChecked bound a1 (Add o1 (Sub n 1))+                 . boundsChecked bound a2 (Add o2 (Sub n 1))+                 $ r |= app "h$compareByteArrays" [a1,o1,a2,o2,n]++  CopyByteArrayOp -> \[] [a1,o1,a2,o2,n] ->+      PrimInline . boundsChecked bound a1 (Add o1 (Sub n 1))+                 . boundsChecked bound a2 (Add o2 (Sub n 1))+                $ loopBlockS (Sub n one_) (.>=. zero_) \i ->+                    [ write_u8 a2 (Add i o2) (read_u8 a1 (Add i o1))+                    , postDecrS i+                    ]+  CopyMutableByteArrayOp       -> \[] xs@[_a1,_o1,_a2,_o2,_n] -> genPrim prof bound ty CopyByteArrayOp [] xs+  CopyByteArrayToAddrOp        -> \[] xs@[_a1,_o1,_a2,_o2,_n] -> genPrim prof bound ty CopyByteArrayOp [] xs+  CopyMutableByteArrayToAddrOp -> \[] xs@[_a1,_o1,_a2,_o2,_n] -> genPrim prof bound ty CopyByteArrayOp [] xs+  CopyAddrToByteArrayOp        -> \[] xs@[_ba,_bo,_aa,_ao,_n] -> genPrim prof bound ty CopyByteArrayOp [] xs++  SetByteArrayOp -> \[] [a,o,n,v] ->+      PrimInline . boundsChecked bound a (Add o (Sub n 1)) $ loopBlockS zero_ (.<. n) \i ->+        [ write_u8 a (Add o i) v+        , postIncrS i+        ]++  AtomicReadByteArrayOp_Int  -> \[r]   [a,i]         -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_i32 a i+  AtomicWriteByteArrayOp_Int -> \[]    [a,i,v]       -> PrimInline . boundsChecked bound a (Add i 3) $ write_i32 a i v+  FetchAddByteArrayOp_Int    -> \[r]   [a,i,v] -> PrimInline . boundsChecked bound a (Add i 3) $ fetchOpByteArray Add  r a i v+  FetchSubByteArrayOp_Int    -> \[r]   [a,i,v] -> PrimInline . boundsChecked bound a (Add i 3) $ fetchOpByteArray Sub  r a i v+  FetchAndByteArrayOp_Int    -> \[r]   [a,i,v] -> PrimInline . boundsChecked bound a (Add i 3) $ fetchOpByteArray BAnd r a i v+  FetchOrByteArrayOp_Int     -> \[r]   [a,i,v] -> PrimInline . boundsChecked bound a (Add i 3) $ fetchOpByteArray BOr  r a i v+  FetchNandByteArrayOp_Int   -> \[r]   [a,i,v] -> PrimInline . boundsChecked bound a (Add i 3) $ fetchOpByteArray (\x y -> BNot (BAnd x y)) r a i v+  FetchXorByteArrayOp_Int    -> \[r]   [a,i,v] -> PrimInline . boundsChecked bound a (Add i 3) $ fetchOpByteArray BXor r a i v++------------------------------- Addr# ------------------------------------------++  AddrAddOp   -> \[a',o'] [a,o,i]         -> PrimInline $ mconcat [a' |= a, o' |= Add o i]+  AddrSubOp   -> \[i]     [_a1,o1,_a2,o2] -> PrimInline $ i |= Sub o1 o2+  AddrRemOp   -> \[r]     [_a,o,i]        -> PrimInline $ r |= Mod o i+  AddrToIntOp -> \[i]     [_a,o]          -> PrimInline $ i |= o -- only usable for comparisons within one range+  IntToAddrOp -> \[a,o]   [i]             -> PrimInline $ mconcat [a |= null_, o |= i]+  AddrGtOp -> \[r] [a1,o1,a2,o2] -> PrimInline $ r |= if10 (app "h$comparePointer" [a1,o1,a2,o2] .>. zero_)+  AddrGeOp -> \[r] [a1,o1,a2,o2] -> PrimInline $ r |= if10 (app "h$comparePointer" [a1,o1,a2,o2] .>=. zero_)+  AddrEqOp -> \[r] [a1,o1,a2,o2] -> PrimInline $ r |= if10 (app "h$comparePointer" [a1,o1,a2,o2] .===. zero_)+  AddrNeOp -> \[r] [a1,o1,a2,o2] -> PrimInline $ r |= if10 (app "h$comparePointer" [a1,o1,a2,o2] .!==. zero_)+  AddrLtOp -> \[r] [a1,o1,a2,o2] -> PrimInline $ r |= if10 (app "h$comparePointer" [a1,o1,a2,o2] .<. zero_)+  AddrLeOp -> \[r] [a1,o1,a2,o2] -> PrimInline $ r |= if10 (app "h$comparePointer" [a1,o1,a2,o2] .<=. zero_)++------------------------------- Addr Indexing: Unboxed Arrays -------------------++  IndexOffAddrOp_Char     -> \[c] [a,o,i] -> PrimInline . boundsChecked bound a (off8  o i) $ c |= read_boff_u8  a (off8  o i)+  IndexOffAddrOp_WideChar -> \[c] [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ c |= read_boff_i32 a (off32 o i)+  IndexOffAddrOp_Int      -> \[c] [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ c |= read_boff_i32 a (off32 o i)+  IndexOffAddrOp_Word     -> \[c] [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ c |= read_boff_u32 a (off32 o i)+  IndexOffAddrOp_Addr     -> \[ca,co] [a,o,i] ->+      PrimInline . boundsChecked bound (a .^ "arr") (off32 o i)+                 $ ifBlockS (a .^ "arr " .&&. a .^ "arr" .! (i .<<. two_))+                       [ ca |= a .^ "arr" .! (off32 o i) .! zero_+                       , co |= a .^ "arr" .! (off32 o i) .! one_+                       ]+                       [ ca |= null_+                       , co |= zero_+                       ]+  IndexOffAddrOp_Float     -> \[c]     [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ c |= read_boff_f32 a (off32 o i)+  IndexOffAddrOp_Double    -> \[c]     [a,o,i] -> PrimInline . boundsChecked bound a (off64 o i) $ c |= read_boff_f64 a (off64 o i)+  IndexOffAddrOp_StablePtr -> \[c1,c2] [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ mconcat+                                                          [ c1 |= var "h$stablePtrBuf"+                                                          , c2 |= read_boff_i32 a (off32 o i)+                                                          ]+  IndexOffAddrOp_Int8  -> \[c]   [a,o,i] -> PrimInline . boundsChecked bound a (off8  o i) $ c |= read_boff_i8  a (off8  o i)+  IndexOffAddrOp_Int16 -> \[c]   [a,o,i] -> PrimInline . boundsChecked bound a (off16 o i) $ c |= read_boff_i16 a (off16 o i)+  IndexOffAddrOp_Int32 -> \[c]   [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ c |= read_boff_i32 a (off32 o i)+  IndexOffAddrOp_Int64 -> \[h,l] [a,o,i] ->+      PrimInline $ mconcat+       [ h |= read_boff_i32 a (Add (off64 o i) (Int 4))+       , l |= read_boff_u32 a (off64 o i)+       ]+  IndexOffAddrOp_Word8  -> \[c]   [a,o,i] -> PrimInline . boundsChecked bound a (off8  o i) $ c |= read_boff_u8  a (off8  o i)+  IndexOffAddrOp_Word16 -> \[c]   [a,o,i] -> PrimInline . boundsChecked bound a (off16 o i) $ c |= read_boff_u16 a (off16 o i)+  IndexOffAddrOp_Word32 -> \[c]   [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ c |= read_boff_u32 a (off32 o i)+  IndexOffAddrOp_Word64 -> \[h,l] [a,o,i] ->+      PrimInline $ mconcat+       [ h |= read_boff_u32 a (Add (off64 o i) (Int 4))+       , l |= read_boff_u32 a (off64 o i)+       ]+  ReadOffAddrOp_Char     -> \[c] [a,o,i] -> PrimInline . boundsChecked bound a (off8  o i) $ c |= read_boff_u8  a (off8  o i)+  ReadOffAddrOp_WideChar -> \[c] [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ c |= read_boff_i32 a (off32 o i)+  ReadOffAddrOp_Int      -> \[c] [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ c |= read_boff_i32 a (off32 o i)+  ReadOffAddrOp_Word     -> \[c] [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ c |= read_boff_u32 a (off32 o i)+  ReadOffAddrOp_Addr     -> \[c1,c2] [a,o,i] ->+      PrimInline $ jVar \x -> mconcat+        [ x |= i .<<. two_+        , boundsChecked bound (a .^ "arr") (Add o x) $+          ifBlockS  (a .^ "arr" .&&. a .^ "arr" .! (Add o x))+              [ c1 |= a .^ "arr" .! (Add o x) .! zero_+              , c2 |= a .^ "arr" .! (Add o x) .! one_+              ]+              [ c1 |= null_+              , c2 |= zero_+              ]+        ]+  ReadOffAddrOp_Float     -> \[c]     [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ c |= read_boff_f32 a (off32 o i)+  ReadOffAddrOp_Double    -> \[c]     [a,o,i] -> PrimInline . boundsChecked bound a (off64 o i) $ c |= read_boff_f64 a (off64 o i)+  ReadOffAddrOp_StablePtr -> \[c1,c2] [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ mconcat+                                                        [ c1 |= var "h$stablePtrBuf"+                                                        , c2 |= read_boff_u32 a (off32 o i)+                                                        ]+  ReadOffAddrOp_Int8   -> \[c]     [a,o,i] -> PrimInline . boundsChecked bound a (off8  o i) $ AssignStat c $ read_boff_i8  a (off8  o i)+  ReadOffAddrOp_Int16  -> \[c]     [a,o,i] -> PrimInline . boundsChecked bound a (off16 o i) $ AssignStat c $ read_boff_i16 a (off16 o i)+  ReadOffAddrOp_Int32  -> \[c]     [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ AssignStat c $ read_boff_i32 a (off32 o i)+  ReadOffAddrOp_Int64  -> \[h,l] [a,o,i] ->+      PrimInline $ mconcat+        [ h |= read_i32 a (Add (off64 o i) (Int 4))+        , l |= read_u32 a (off64 o i)+        ]+  ReadOffAddrOp_Word8  -> \[c]     [a,o,i] -> PrimInline . boundsChecked bound a (off8  o i) $ AssignStat c $ read_boff_u8  a (off8  o i)+  ReadOffAddrOp_Word16 -> \[c]     [a,o,i] -> PrimInline . boundsChecked bound a (off16 o i) $ AssignStat c $ read_boff_u16 a (off16 o i)+  ReadOffAddrOp_Word32 -> \[c]     [a,o,i] -> PrimInline . boundsChecked bound a (off32 o i) $ AssignStat c $ read_boff_u32 a (off32 o i)+  ReadOffAddrOp_Word64 -> \[c1,c2] [a,o,i] ->+      PrimInline $ mconcat+       [ c1 |= read_boff_u32 a (Add (off64 o i) (Int 4))+       , c2 |= read_boff_u32 a (off64 o i)+       ]+  WriteOffAddrOp_Char     -> \[] [a,o,i,v]     -> PrimInline . boundsChecked bound a (off8  o i) $ write_boff_u8  a (off8  o i) v+  WriteOffAddrOp_WideChar -> \[] [a,o,i,v]     -> PrimInline . boundsChecked bound a (off32 o i) $ write_boff_i32 a (off32 o i) v+  WriteOffAddrOp_Int      -> \[] [a,o,i,v]     -> PrimInline . boundsChecked bound a (off32 o i) $ write_boff_i32 a (off32 o i) v+  WriteOffAddrOp_Word     -> \[] [a,o,i,v]     -> PrimInline . boundsChecked bound a (off32 o i) $ write_boff_u32 a (off32 o i) v+  WriteOffAddrOp_Addr     -> \[] [a,o,i,va,vo] ->+      PrimInline $ mconcat+        [ ifS (Not (a .^ "arr")) (a .^ "arr" |= ValExpr (JList [])) mempty+        , boundsChecked bound (a .^ "arr") (off32 o i) $+            AssignStat (a .^ "arr" .! (off32 o i)) $ ValExpr (JList [va, vo])+        ]+  WriteOffAddrOp_Float     -> \[] [a,o,i,v]      -> PrimInline . boundsChecked bound a (off32 o i) $ write_boff_f32 a (off32 o i) v+  WriteOffAddrOp_Double    -> \[] [a,o,i,v]      -> PrimInline . boundsChecked bound a (off64 o i) $ write_boff_f64 a (off64 o i) v+  WriteOffAddrOp_StablePtr -> \[] [a,o,i,_v1,v2] -> PrimInline . boundsChecked bound a (off32 o i) $ write_boff_u32 a (off32 o i) v2+  WriteOffAddrOp_Int8      -> \[] [a,o,i,v]      -> PrimInline . boundsChecked bound a (off8  o i) $ write_boff_i8  a (off8  o i) v+  WriteOffAddrOp_Int16     -> \[] [a,o,i,v]      -> PrimInline . boundsChecked bound a (off16 o i) $ write_boff_i16 a (off16 o i) v+  WriteOffAddrOp_Int32     -> \[] [a,o,i,v]      -> PrimInline . boundsChecked bound a (off32 o i) $ write_boff_i32 a (off32 o i) v+  WriteOffAddrOp_Int64     -> \[] [a,o,i,v1,v2]  -> PrimInline . boundsChecked bound a (off64 o i) $ mconcat+                                                      [ write_boff_i32 a (Add (off64 o i) (Int 4)) v1+                                                      , write_boff_u32 a (off64 o i) v2+                                                      ]+  WriteOffAddrOp_Word8     -> \[] [a,o,i,v]      -> PrimInline . boundsChecked bound a (off8  o i) $ write_boff_u8  a (off8  o i) v+  WriteOffAddrOp_Word16    -> \[] [a,o,i,v]      -> PrimInline . boundsChecked bound a (off16 o i) $ write_boff_u16 a (off16 o i) v+  WriteOffAddrOp_Word32    -> \[] [a,o,i,v]      -> PrimInline . boundsChecked bound a (off32 o i) $ write_boff_u32 a (off32 o i) v+  WriteOffAddrOp_Word64    -> \[] [a,o,i,v1,v2]  -> PrimInline . boundsChecked bound a (off64 o i) $ mconcat+                                                      [ write_boff_u32 a (Add (off64 o i) (Int 4)) v1+                                                      , write_boff_u32 a (off64 o i) v2+                                                      ]+-- Mutable variables+  NewMutVarOp           -> \[r] [x]       -> PrimInline $ r |= New (app "h$MutVar" [x])+  ReadMutVarOp          -> \[r] [m]       -> PrimInline $ r |= m .^ "val"+  WriteMutVarOp         -> \[] [m,x]      -> PrimInline $ m .^ "val" |= x+  AtomicModifyMutVar2Op -> \[r1,r2] [m,f] -> PrimInline $ appT [r1,r2] "h$atomicModifyMutVar2" [m,f]+  AtomicModifyMutVar_Op -> \[r1,r2] [m,f] -> PrimInline $ appT [r1,r2] "h$atomicModifyMutVar" [m,f]++  CasMutVarOp -> \[status,r] [mv,o,n] -> PrimInline $ ifS (mv .^ "val" .===. o)+                   (mconcat [status |= zero_, r |= n, mv .^ "val" |= n])+                   (mconcat [status |= one_ , r |= mv .^ "val"])++------------------------------- Exceptions --------------------------------------++  CatchOp -> \[_r] [a,handler] -> PRPrimCall $ returnS (app "h$catch" [a, handler])++                             -- fully ignore the result arity as it can use 1 or 2+                             -- slots, depending on the return type.+  RaiseOp                 -> \_r [a] -> PRPrimCall $ returnS (app "h$throw" [a, false_])+  RaiseIOOp               -> \_r [a] -> PRPrimCall $ returnS (app "h$throw" [a, false_])+  RaiseUnderflowOp        -> \_r []  -> PRPrimCall $ returnS (app "h$throw" [var "h$baseZCGHCziExceptionziTypeziunderflowException", false_])+  RaiseOverflowOp         -> \_r []  -> PRPrimCall $ returnS (app "h$throw" [var "h$baseZCGHCziExceptionziTypezioverflowException", false_])+  RaiseDivZeroOp          -> \_r []  -> PRPrimCall $ returnS (app "h$throw" [var "h$baseZCGHCziExceptionziTypezidivZZeroException", false_])+  MaskAsyncExceptionsOp   -> \_r [a] -> PRPrimCall $ returnS (app "h$maskAsync" [a])+  MaskUninterruptibleOp   -> \_r [a] -> PRPrimCall $ returnS (app "h$maskUnintAsync" [a])+  UnmaskAsyncExceptionsOp -> \_r [a] -> PRPrimCall $ returnS (app "h$unmaskAsync" [a])++  MaskStatus -> \[r] [] -> PrimInline $ r |= app "h$maskStatus" []++------------------------------- STM-accessible Mutable Variables  --------------++  AtomicallyOp -> \[_r] [a]   -> PRPrimCall $ returnS (app "h$atomically" [a])+  RetryOp      -> \_r   []    -> PRPrimCall $ returnS (app "h$stmRetry" [])+  CatchRetryOp -> \[_r] [a,b] -> PRPrimCall $ returnS (app "h$stmCatchRetry" [a,b])+  CatchSTMOp   -> \[_r] [a,h] -> PRPrimCall $ returnS (app "h$catchStm" [a,h])+  NewTVarOp    -> \[tv] [v]   -> PrimInline $ tv |= app "h$newTVar" [v]+  ReadTVarOp   -> \[r] [tv]   -> PrimInline $ r |= app "h$readTVar" [tv]+  ReadTVarIOOp -> \[r] [tv]   -> PrimInline $ r |= app "h$readTVarIO" [tv]+  WriteTVarOp  -> \[] [tv,v]  -> PrimInline $ appS "h$writeTVar" [tv,v]++------------------------------- Synchronized Mutable Variables ------------------++  NewMVarOp     -> \[r]   []    -> PrimInline $ r |= New (app "h$MVar" [])+  TakeMVarOp    -> \[_r]  [m]   -> PRPrimCall $ returnS (app "h$takeMVar" [m])+  TryTakeMVarOp -> \[r,v] [m]   -> PrimInline $ appT [r,v] "h$tryTakeMVar" [m]+  PutMVarOp     -> \[]    [m,v] -> PRPrimCall $ returnS (app "h$putMVar" [m,v])+  TryPutMVarOp  -> \[r]   [m,v] -> PrimInline $ r |= app "h$tryPutMVar" [m,v]+  ReadMVarOp    -> \[_r]  [m]   -> PRPrimCall $ returnS (app "h$readMVar" [m])+  TryReadMVarOp -> \[r,v] [m]   -> PrimInline $ mconcat+                                                    [ v |= m .^ "val"+                                                    , r |= if01 (v .===. null_)+                                                    ]+  IsEmptyMVarOp -> \[r]   [m]   -> PrimInline $ r |= if10 (m .^ "val" .===. null_)++------------------------------- Delay/Wait Ops ---------------------------------++  DelayOp     -> \[] [t]  -> PRPrimCall $ returnS (app "h$delayThread" [t])+  WaitReadOp  -> \[] [fd] -> PRPrimCall $ returnS (app "h$waidRead" [fd])+  WaitWriteOp -> \[] [fd] -> PRPrimCall $ returnS (app "h$waitWrite" [fd])++------------------------------- Concurrency Primitives -------------------------++  ForkOp   -> \[_tid] [x]    -> PRPrimCall $ returnS (app "h$fork" [x, true_])+  ForkOnOp -> \[_tid] [_p,x] -> PRPrimCall $ returnS (app "h$fork" [x, true_]) -- ignore processor argument+  KillThreadOp  -> \[] [tid,ex]  -> PRPrimCall $ returnS (app "h$killThread" [tid,ex])+  YieldOp       -> \[] []        -> PRPrimCall $ returnS (app "h$yield" [])+  MyThreadIdOp  -> \[r] []       -> PrimInline $ r |= var "h$currentThread"+  IsCurrentThreadBoundOp -> \[r] [] -> PrimInline $ r |= one_+  NoDuplicateOp -> \[] [] -> PrimInline mempty -- don't need to do anything as long as we have eager blackholing+  ThreadStatusOp -> \[stat,cap,locked] [tid] -> PrimInline $ appT [stat, cap, locked] "h$threadStatus" [tid]+  ListThreadsOp  -> \[r] [] -> PrimInline $ r |= var "h$threads"+  GetThreadLabelOp -> \[r1, r2] [t] -> PrimInline $ appT [r1, r2] "h$getThreadLabel" [t]+  LabelThreadOp    -> \[] [t,l] -> PrimInline $ t .^ "label" |= l++------------------------------- Weak Pointers -----------------------------------++  MkWeakOp              -> \[r] [o,b,c] -> PrimInline $ r |= app "h$makeWeak" [o,b,c]+  MkWeakNoFinalizerOp   -> \[r] [o,b]   -> PrimInline $ r |= app "h$makeWeakNoFinalizer" [o,b]+  AddCFinalizerToWeakOp -> \[r] [_a1,_a1o,_a2,_a2o,_i,_a3,_a3o,_w] -> PrimInline $ r |= one_+  DeRefWeakOp           -> \[f,v] [w] -> PrimInline $ mconcat+                                                        [ v |= w .^ "val"+                                                        , f |= if01 (v .===. null_)+                                                        ]+  FinalizeWeakOp     -> \[fl,fin] [w] -> PrimInline $ appT [fin, fl] "h$finalizeWeak" [w]+  TouchOp            -> \[] [_e]      -> PrimInline mempty+  KeepAliveOp        -> \[_r] [x, f]  -> PRPrimCall $ ReturnStat (app "h$keepAlive" [x, f])+++------------------------------ Stable pointers and names ------------------------++  MakeStablePtrOp -> \[s1,s2] [a] -> PrimInline $ mconcat+      [ s1 |= var "h$stablePtrBuf"+      , s2 |= app "h$makeStablePtr" [a]+      ]+  DeRefStablePtrOp -> \[r] [_s1,s2]            -> PrimInline $ r |= app "h$deRefStablePtr" [s2]+  EqStablePtrOp    -> \[r] [_sa1,sa2,_sb1,sb2] -> PrimInline $ r |= if10 (sa2 .===. sb2)++  MakeStableNameOp  -> \[r] [a] -> PrimInline $ r |= app "h$makeStableName" [a]+  StableNameToIntOp -> \[r] [s] -> PrimInline $ r |= app "h$stableNameInt" [s]++------------------------------ Compact normal form -----------------------------++  CompactNewOp           -> \[c] [s]   -> PrimInline $ c |= app "h$compactNew" [s]+  CompactResizeOp        -> \[]  [c,s] -> PrimInline $ appS "h$compactResize" [c,s]+  CompactContainsOp      -> \[r] [c,v] -> PrimInline $ r |= app "h$compactContains" [c,v]+  CompactContainsAnyOp   -> \[r] [v]   -> PrimInline $ r |= app "h$compactContainsAny" [v]+  CompactGetFirstBlockOp -> \[ra,ro,s] [c] ->+    PrimInline $ appT [ra,ro,s] "h$compactGetFirstBlock" [c]+  CompactGetNextBlockOp -> \[ra,ro,s] [c,a,o] ->+    PrimInline $ appT [ra,ro,s] "h$compactGetNextBlock" [c,a,o]+  CompactAllocateBlockOp -> \[ra,ro] [size,sa,so] ->+    PrimInline $ appT [ra,ro] "h$compactAllocateBlock" [size,sa,so]+  CompactFixupPointersOp -> \[c,newroota, newrooto] [blocka,blocko,roota,rooto] ->+    PrimInline $ appT [c,newroota,newrooto] "h$compactFixupPointers" [blocka,blocko,roota,rooto]+  CompactAdd -> \[_r] [c,o] ->+    PRPrimCall $ returnS (app "h$compactAdd" [c,o])+  CompactAddWithSharing -> \[_r] [c,o] ->+    PRPrimCall $ returnS (app "h$compactAddWithSharing" [c,o])+  CompactSize -> \[s] [c] ->+    PrimInline $ s |= app "h$compactSize" [c]++------------------------------ Unsafe pointer equality --------------------------++  ReallyUnsafePtrEqualityOp -> \[r] [p1,p2] -> PrimInline $ r |= if10 (p1 .===. p2)++------------------------------ Parallelism --------------------------------------++  ParOp     -> \[r] [_a] -> PrimInline $ r |= zero_+  SparkOp   -> \[r] [a]  -> PrimInline $ r |= a+  SeqOp     -> \[_r] [e] -> PRPrimCall $ returnS (app "h$e" [e])+  NumSparks -> \[r] []   -> PrimInline $ r |= zero_++------------------------------ Tag to enum stuff --------------------------------++  DataToTagOp -> \[_r] [d] -> PRPrimCall $ mconcat+      [ stack .! PreInc sp |= var "h$dataToTag_e"+      , returnS (app "h$e" [d])+      ]+  TagToEnumOp -> \[r] [tag] -> if+    | isBoolTy ty -> PrimInline $ r |= IfExpr tag true_ false_+    | otherwise   -> PrimInline $ r |= app "h$tagToEnum" [tag]++------------------------------ Bytecode operations ------------------------------++  AddrToAnyOp -> \[r] [d,_o] -> PrimInline $ r |= d++------------------------------ Profiling (CCS)  ------------------------------++  GetCCSOfOp -> \[a, o] [obj] -> if+    | prof -> PrimInline $ mconcat+        [ a |= if_ (isObject obj)+                    (app "h$buildCCSPtr" [obj .^ "cc"])+                    null_+        , o |= zero_+        ]+    | otherwise -> PrimInline $ mconcat+                    [ a |= null_+                    , o |= zero_+                    ]++  GetCurrentCCSOp -> \[a, o] [_dummy_arg] ->+    let ptr = if prof then app "h$buildCCSPtr" [jCurrentCCS]+                      else null_+    in PrimInline $ mconcat+        [ a |= ptr+        , o |= zero_+        ]++  ClearCCSOp -> \[_r] [x] -> PRPrimCall $ ReturnStat (app "h$clearCCS" [x])++------------------------------ Eventlog -------------------++  TraceEventOp       -> \[] [ed,eo]     -> PrimInline $ appS "h$traceEvent" [ed,eo]+  TraceEventBinaryOp -> \[] [ed,eo,len] -> PrimInline $ appS "h$traceEventBinary" [ed,eo,len]+  TraceMarkerOp      -> \[] [ed,eo]     -> PrimInline $ appS "h$traceMarker" [ed,eo]++  IndexByteArrayOp_Word8AsChar      -> \[r] [a,i] -> PrimInline . boundsChecked bound a i         $ r |= read_boff_u8  a i+  IndexByteArrayOp_Word8AsWideChar  -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_boff_i32 a i+  IndexByteArrayOp_Word8AsAddr      -> \[r1,r2] [a,i] ->+      PrimInline $ jVar \x -> mconcat+        [ x |= i .<<. two_+        , boundsChecked bound (a .^ "arr") x $+          ifS (a .^ "arr" .&&. a .^ "arr" .! x)+               (mconcat [ r1 |= a .^ "arr" .! x .! zero_+                        , r2 |= a .^ "arr" .! x .! one_+                        ])+               (mconcat [r1 |= null_, r2 |= one_])+        ]+  IndexByteArrayOp_Word8AsFloat     -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_boff_f32 a i+  IndexByteArrayOp_Word8AsDouble    -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 7) $ r |= read_boff_f64 a i+  IndexByteArrayOp_Word8AsStablePtr -> \[r1,r2] [a,i] ->+    PrimInline $ mconcat+    [ r1 |= var "h$stablePtrBuf"+    , r2 |= read_boff_i32 a i+    ]+  IndexByteArrayOp_Word8AsInt16     -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 1) $ r |= read_boff_i16 a i+  IndexByteArrayOp_Word8AsInt32     -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_boff_i32 a i+  IndexByteArrayOp_Word8AsInt64     -> \[h,l] [a,i] ->+    PrimInline $ mconcat+        [ h |= read_boff_i32 a (Add i (Int 4))+        , l |= read_boff_u32 a i+        ]+  IndexByteArrayOp_Word8AsInt       -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_boff_i32  a i+  IndexByteArrayOp_Word8AsWord16    -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 1) $ r |= read_boff_u16  a i+  IndexByteArrayOp_Word8AsWord32    -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_boff_u32  a i+  IndexByteArrayOp_Word8AsWord64    -> \[h,l] [a,i] ->+    PrimInline . boundsChecked bound a (Add i 7) $ mconcat+        [ h |= read_boff_u32 a (Add i (Int 4))+        , l |= read_boff_u32 a i+        ]+  IndexByteArrayOp_Word8AsWord      -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_boff_u32  a i++  ReadByteArrayOp_Word8AsChar       -> \[r] [a,i] -> PrimInline . boundsChecked bound a i         $ r |= read_boff_u8  a i+  ReadByteArrayOp_Word8AsWideChar   -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_boff_i32 a i+  ReadByteArrayOp_Word8AsAddr       -> \[r1,r2] [a,i] ->+      PrimInline $ jVar \x -> mconcat+        [ x |= i .<<. two_+        , boundsChecked bound (a .^ "arr") x $+          ifS (a .^ "arr" .&&. a .^ "arr" .! x)+               (mconcat [ r1 |= a .^ "arr" .! x .! zero_+                        , r2 |= a .^ "arr" .! x .! one_+                        ])+               (mconcat [r1 |= null_, r2 |= one_])+        ]+  ReadByteArrayOp_Word8AsFloat      -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_boff_f32 a i+  ReadByteArrayOp_Word8AsDouble     -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 7) $ r |= read_boff_f64 a i+  ReadByteArrayOp_Word8AsStablePtr  -> \[r1,r2] [a,i] ->+    PrimInline $ mconcat+    [ r1 |= var "h$stablePtrBuf"+    , r2 |= read_boff_i32 a i+    ]+  ReadByteArrayOp_Word8AsInt16      -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 1) $ r |= read_boff_i16 a i+  ReadByteArrayOp_Word8AsInt32      -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_boff_i32 a i+  ReadByteArrayOp_Word8AsInt64      -> \[h,l] [a,i] ->+    PrimInline $ mconcat+      [ h |= read_boff_i32 a (Add i (Int 4))+      , l |= read_boff_u32 a i+      ]+  ReadByteArrayOp_Word8AsInt        -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_boff_i32  a i+  ReadByteArrayOp_Word8AsWord16     -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 1) $ r |= read_boff_u16  a i+  ReadByteArrayOp_Word8AsWord32     -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_boff_u32  a i+  ReadByteArrayOp_Word8AsWord64     -> \[h,l] [a,i] ->+    PrimInline . boundsChecked bound a (Add i 7) $ mconcat+        [ h |= read_boff_u32 a (Add i (Int 4))+        , l |= read_boff_u32 a i+        ]+  ReadByteArrayOp_Word8AsWord       -> \[r] [a,i] -> PrimInline . boundsChecked bound a (Add i 3) $ r |= read_boff_u32  a i++  WriteByteArrayOp_Word8AsChar      -> \[] [a,i,e] -> PrimInline . boundsChecked bound a i         $ write_boff_i8  a i e+  WriteByteArrayOp_Word8AsWideChar  -> \[] [a,i,e] -> PrimInline . boundsChecked bound a (Add i 3) $ write_boff_i32 a i e+  WriteByteArrayOp_Word8AsAddr      -> \[] [a,i,e1,e2] ->+    PrimInline $ mconcat+      [ ifS (Not (a .^ "arr")) (a .^ "arr" |= ValExpr (JList [])) mempty+      , boundsChecked bound (a .^ "arr") (i .<<. two_) $+          a .^ "arr" .! (i .<<. two_) |= ValExpr (JList [e1, e2])+      ]++  WriteByteArrayOp_Word8AsFloat     -> \[] [a,i,e] -> PrimInline . boundsChecked bound a (Add i 3) $ write_boff_f32 a i e+  WriteByteArrayOp_Word8AsDouble    -> \[] [a,i,e] -> PrimInline . boundsChecked bound a (Add i 7) $ write_boff_f64 a i e+  WriteByteArrayOp_Word8AsStablePtr -> \[] [a,i,_e1,e2] -> PrimInline . boundsChecked bound a (Add i 3) $ write_boff_i32 a i e2+  WriteByteArrayOp_Word8AsInt16     -> \[] [a,i,e] -> PrimInline . boundsChecked bound a (Add i 1) $ write_boff_i16 a i e+  WriteByteArrayOp_Word8AsInt32     -> \[] [a,i,e] -> PrimInline . boundsChecked bound a (Add i 3) $ write_boff_i32 a i e+  WriteByteArrayOp_Word8AsInt64     -> \[] [a,i,h,l] ->+    -- JS Numbers are little-endian and 32-bit, so write the lower 4 bytes at i+    -- then write the higher 4 bytes to i+4+    PrimInline . boundsChecked bound a i+               $ mconcat [ write_boff_i32 a (Add i (Int 4)) h+                         , write_boff_u32 a i               l+                         ]+  WriteByteArrayOp_Word8AsInt       -> \[] [a,i,e] -> PrimInline . boundsChecked bound a (Add i 3) $ write_boff_i32 a i e+  WriteByteArrayOp_Word8AsWord16    -> \[] [a,i,e] -> PrimInline . boundsChecked bound a (Add i 1) $ write_boff_u16 a i e+  WriteByteArrayOp_Word8AsWord32    -> \[] [a,i,e] -> PrimInline . boundsChecked bound a (Add i 3) $ write_boff_u32 a i e+  WriteByteArrayOp_Word8AsWord64    -> \[] [a,i,h,l] ->+    PrimInline . boundsChecked bound a (Add i 7)+               $ mconcat [ write_boff_u32 a  (Add i (Int 4)) h+                         , write_boff_u32 a  i               l+                         ]+  WriteByteArrayOp_Word8AsWord      -> \[] [a,i,e] -> PrimInline . boundsChecked bound a (Add i 3) $ write_boff_u32 a i e++  CasByteArrayOp_Int                -> \[r] [a,i,old,new] -> PrimInline . boundsChecked bound a (Add i 3) $ casOp read_i32 write_i32 r a i old new+  CasByteArrayOp_Int8               -> \[r] [a,i,old,new] -> PrimInline . boundsChecked bound a i         $ casOp read_i8  write_i8  r a i old new+  CasByteArrayOp_Int16              -> \[r] [a,i,old,new] -> PrimInline . boundsChecked bound a (Add i 1) $ casOp read_i16 write_i16 r a i old new+  CasByteArrayOp_Int32              -> \[r] [a,i,old,new] -> PrimInline . boundsChecked bound a (Add i 3) $ casOp read_i32 write_i32 r a i old new++  CasByteArrayOp_Int64              -> \[r_h,r_l] [a,i,old_h,old_l,new_h,new_l] -> PrimInline . boundsChecked bound a (Add (i .<<. one_) one_) $+    jVar \t_h t_l -> mconcat [ t_h |= read_i32 a (Add (i .<<. one_) one_)+                             , t_l |= read_u32 a (i .<<. one_)+                             , r_h |= t_h+                             , r_l |= t_l+                             , ifS (t_l .===. old_l) -- small optimization, check low bits first, fail fast+                                   (ifBlockS (t_h .===. old_h)+                                            -- Pre-Condition is good, do the write+                                             [ write_i32 a (Add (i .<<. one_) one_) new_h+                                             , write_u32 a (i .<<. one_)            new_l+                                             ]+                                             -- no good, don't write+                                             mempty)+                                   mempty+                             ]++  CasAddrOp_Addr                    -> \[r_a,r_o] [a1,o1,a2,o2,a3,o3] -> PrimInline $+                    mconcat [ ifS (app "h$comparePointer" [a1,o1,a2,o2])+                                  (appS "h$memcpy" [a3,o3,a1,o1,8])+                                  mempty+                            , r_a |= a1+                            , r_o |= o1+                            ]+  CasAddrOp_Word                    -> \[r] [a,o,old,new] -> PrimInline $ casOp read_u32 write_u32 r a o old new+  CasAddrOp_Word8                   -> \[r] [a,o,old,new] -> PrimInline $ casOp read_u8  write_u8  r a o old new+  CasAddrOp_Word16                  -> \[r] [a,o,old,new] -> PrimInline $ casOp read_u16 write_u16 r a o old new+  CasAddrOp_Word32                  -> \[r] [a,o,old,new] -> PrimInline $ casOp read_u32 write_u32 r a o old new+  CasAddrOp_Word64                  -> \[r_h,r_l] [a,o,old_h,old_l,new_h,new_l] -> PrimInline $+                     mconcat [ r_h |= read_u32 a (Add o (Int 4))+                             , r_l |= read_u32 a o+                             , ifS (r_l .===. old_l)+                                   (ifBlockS (r_h .===. old_h)+                                             [ write_u32 a (Add o (Int 4)) new_h+                                             , write_u32 a o               new_l+                                             ]+                                             mempty)+                               mempty+                             ]++  FetchAddAddrOp_Word               -> \[r] [a,o,v] -> PrimInline $ fetchOpAddr Add r a o v+  FetchSubAddrOp_Word               -> \[r] [a,o,v] -> PrimInline $ fetchOpAddr Sub  r a o v+  FetchAndAddrOp_Word               -> \[r] [a,o,v] -> PrimInline $ fetchOpAddr BAnd  r a o v+  FetchNandAddrOp_Word              -> \[r] [a,o,v] -> PrimInline $ fetchOpAddr ((BNot .) . BAnd) r a o v+  FetchOrAddrOp_Word                -> \[r] [a,o,v] -> PrimInline $ fetchOpAddr BOr   r a o v+  FetchXorAddrOp_Word               -> \[r] [a,o,v] -> PrimInline $ fetchOpAddr BXor  r a o v++  InterlockedExchange_Addr          -> \[r_a,r_o] [a1,o1,_a2,o2] -> PrimInline $+                                          -- this primop can't be implemented+                                          -- correctly because we don't store+                                          -- the array reference part of an Addr#,+                                          -- only the offset part.+                                          --+                                          -- So let's assume that all the array+                                          -- references are the same...+                                          --+                                          -- Note: we could generate an assert+                                          -- that checks that a1 === a2. However+                                          -- we can't check that the Addr# read+                                          -- at Addr# a2[o2] also comes from this+                                          -- a1/a2 array.+                                          mconcat [ r_a |= a1 -- might be wrong (see above)+                                                  , r_o |= read_boff_u32 a1 o1+                                                  -- TODO (see above)+                                                  -- assert that a1 === a2+                                                  , write_boff_u32 a1 o1 o2+                                                  ]+  InterlockedExchange_Word          -> \[r] [a,o,w] -> PrimInline $+                                                       mconcat [ r |= read_boff_u32 a o+                                                               , write_boff_u32 a o w+                                                               ]++  ShrinkSmallMutableArrayOp_Char    -> \[]  [a,n] -> PrimInline $ appS "h$shrinkMutableCharArray" [a,n]+  GetSizeofSmallMutableArrayOp      -> \[r] [a]   -> PrimInline $ r |= a .^ "length"++  AtomicReadAddrOp_Word             -> \[r] [a,o]   -> PrimInline $ r |= read_boff_u32 a o+  AtomicWriteAddrOp_Word            -> \[]  [a,o,w] -> PrimInline $ write_boff_u32 a o w+++------------------------------ Unhandled primops -------------------++  NewPromptTagOp                    -> unhandledPrimop op+  PromptOp                          -> unhandledPrimop op+  Control0Op                        -> unhandledPrimop op++  NewIOPortOp                       -> unhandledPrimop op+  ReadIOPortOp                      -> unhandledPrimop op+  WriteIOPortOp                     -> unhandledPrimop op++  GetSparkOp                        -> unhandledPrimop op+  AnyToAddrOp                       -> unhandledPrimop op+  MkApUpd0_Op                       -> unhandledPrimop op+  NewBCOOp                          -> unhandledPrimop op+  UnpackClosureOp                   -> unhandledPrimop op+  ClosureSizeOp                     -> unhandledPrimop op+  GetApStackValOp                   -> unhandledPrimop op+  WhereFromOp                       -> unhandledPrimop op -- should be easily implementable with o.f.n++  SetThreadAllocationCounter        -> unhandledPrimop op++------------------------------- Vector -----------------------------------------+-- For now, vectors are unsupported on the JS backend. Simply put, they do not+-- make much sense to support given support for arrays and lack of SIMD support+-- in JS. We could try to roll something special but we would not be able to+-- give any performance guarentees to the user and so we leave these has+-- unhandled for now.+  VecBroadcastOp _ _ _              -> unhandledPrimop op+  VecPackOp _ _ _                   -> unhandledPrimop op+  VecUnpackOp _ _ _                 -> unhandledPrimop op+  VecInsertOp _ _ _                 -> unhandledPrimop op+  VecAddOp _ _ _                    -> unhandledPrimop op+  VecSubOp _ _ _                    -> unhandledPrimop op+  VecMulOp _ _ _                    -> unhandledPrimop op+  VecDivOp _ _ _                    -> unhandledPrimop op+  VecQuotOp _ _ _                   -> unhandledPrimop op+  VecRemOp _ _ _                    -> unhandledPrimop op+  VecNegOp _ _ _                    -> unhandledPrimop op+  VecIndexByteArrayOp _ _ _         -> unhandledPrimop op+  VecReadByteArrayOp _ _ _          -> unhandledPrimop op+  VecWriteByteArrayOp _ _ _         -> unhandledPrimop op+  VecIndexOffAddrOp _ _ _           -> unhandledPrimop op+  VecReadOffAddrOp _ _ _            -> unhandledPrimop op+  VecWriteOffAddrOp _ _ _           -> unhandledPrimop op++  VecIndexScalarByteArrayOp _ _ _   -> unhandledPrimop op+  VecReadScalarByteArrayOp _ _ _    -> unhandledPrimop op+  VecWriteScalarByteArrayOp _ _ _   -> unhandledPrimop op+  VecIndexScalarOffAddrOp _ _ _     -> unhandledPrimop op+  VecReadScalarOffAddrOp _ _ _      -> unhandledPrimop op+  VecWriteScalarOffAddrOp _ _ _     -> unhandledPrimop op++  PrefetchByteArrayOp3              -> noOp+  PrefetchMutableByteArrayOp3       -> noOp+  PrefetchAddrOp3                   -> noOp+  PrefetchValueOp3                  -> noOp+  PrefetchByteArrayOp2              -> noOp+  PrefetchMutableByteArrayOp2       -> noOp+  PrefetchAddrOp2                   -> noOp+  PrefetchValueOp2                  -> noOp+  PrefetchByteArrayOp1              -> noOp+  PrefetchMutableByteArrayOp1       -> noOp+  PrefetchAddrOp1                   -> noOp+  PrefetchValueOp1                  -> noOp+  PrefetchByteArrayOp0              -> noOp+  PrefetchMutableByteArrayOp0       -> noOp+  PrefetchAddrOp0                   -> noOp+  PrefetchValueOp0                  -> noOp++unhandledPrimop :: PrimOp -> [JExpr] -> [JExpr] -> PrimRes+unhandledPrimop op rs as = PrimInline $ mconcat+  [ appS "h$log" [toJExpr $ mconcat+      [ "warning, unhandled primop: "+      , renderWithContext defaultSDocContext (ppr op)+      , " "+      , show (length rs, length as)+      ]]+  , appS (mkFastString $ "h$primop_" ++ zEncodeString (renderWithContext defaultSDocContext (ppr op))) as+    -- copyRes+  , mconcat $ zipWith (\r reg -> r |= toJExpr reg) rs (enumFrom Ret1)+  ]++-- | A No Op, used for primops the JS platform cannot or do not support. For+-- example, the prefetching primops do not make sense on the JS platform because+-- we do not have enough control over memory to provide any kind of prefetching+-- mechanism. Hence, these are NoOps.+noOp :: Foldable f => f a -> f a -> PrimRes+noOp = const . const $ PrimInline mempty++-- tuple returns+appT :: [JExpr] -> FastString -> [JExpr] -> JStat+appT []     f xs = appS f xs+appT (r:rs) f xs = mconcat+  [ r |= app f xs+  , mconcat (zipWith (\r ret -> r |= toJExpr ret) rs (enumFrom Ret1))+  ]++--------------------------------------------+-- ByteArray indexing+--------------------------------------------++-- For every ByteArray, the RTS creates the following views:+--  i3: Int32 view+--  u8: Word8 view+--  u1: Word16 view+--  f3: Float32 view+--  f6: Float64 view+--  dv: generic DataView+-- It seems a bit weird to mix Int and Word views like this, but perhaps they+-- are the more common.+--+-- See 'h$newByteArray' in 'ghc/rts/js/mem.js' for details.+--+-- Note that *byte* indexing can only be done with the generic DataView. Use+-- read_boff_* and write_boff_* for this.+--+-- Other read_* and write_* helpers directly use the more specific views.+-- Prefer using them over idx_* to make your intent clearer.++idx_i32, idx_u8, idx_u16, idx_f64, idx_f32 :: JExpr -> JExpr -> JExpr+idx_i32 a i = IdxExpr (a .^ "i3") i+idx_u8  a i = IdxExpr (a .^ "u8") i+idx_u16 a i = IdxExpr (a .^ "u1") i+idx_f64 a i = IdxExpr (a .^ "f6") i+idx_f32 a i = IdxExpr (a .^ "f3") i++read_u8 :: JExpr -> JExpr -> JExpr+read_u8 a i = idx_u8 a i++read_u16 :: JExpr -> JExpr -> JExpr+read_u16 a i = idx_u16 a i++read_u32 :: JExpr -> JExpr -> JExpr+read_u32 a i = toU32 (idx_i32 a i)++read_i8 :: JExpr -> JExpr -> JExpr+read_i8 a i = signExtend8 (idx_u8 a i)++read_i16 :: JExpr -> JExpr -> JExpr+read_i16 a i = signExtend16 (idx_u16 a i)++read_i32 :: JExpr -> JExpr -> JExpr+read_i32 a i = idx_i32 a i++read_f32 :: JExpr -> JExpr -> JExpr+read_f32 a i = idx_f32 a i++read_f64 :: JExpr -> JExpr -> JExpr+read_f64 a i = idx_f64 a i++write_u8 :: JExpr -> JExpr -> JExpr -> JStat+write_u8 a i v = idx_u8 a i |= v++write_u16 :: JExpr -> JExpr -> JExpr -> JStat+write_u16 a i v = idx_u16 a i |= v++write_u32 :: JExpr -> JExpr -> JExpr -> JStat+write_u32 a i v = idx_i32 a i |= v++write_i8 :: JExpr -> JExpr -> JExpr -> JStat+write_i8 a i v = idx_u8 a i |= v++write_i16 :: JExpr -> JExpr -> JExpr -> JStat+write_i16 a i v = idx_u16 a i |= v++write_i32 :: JExpr -> JExpr -> JExpr -> JStat+write_i32 a i v = idx_i32 a i |= v++write_f32 :: JExpr -> JExpr -> JExpr -> JStat+write_f32 a i v = idx_f32 a i |= v++write_f64 :: JExpr -> JExpr -> JExpr -> JStat+write_f64 a i v = idx_f64 a i |= v++-- Data View helper functions: byte indexed!+--+-- The argument list consists of the array @a@, the index @i@, and the new value+-- to set (in the case of a setter) @v@.++write_boff_i8, write_boff_u8, write_boff_i16, write_boff_u16, write_boff_i32, write_boff_u32, write_boff_f32, write_boff_f64 :: JExpr -> JExpr -> JExpr -> JStat+write_boff_i8  a i v = write_i8 a i v+write_boff_u8  a i v = write_u8 a i v+write_boff_i16 a i v = ApplStat (a .^ "dv" .^ "setInt16"  ) [i, v, true_]+write_boff_u16 a i v = ApplStat (a .^ "dv" .^ "setUint16" ) [i, v, true_]+write_boff_i32 a i v = ApplStat (a .^ "dv" .^ "setInt32"  ) [i, v, true_]+write_boff_u32 a i v = ApplStat (a .^ "dv" .^ "setUint32" ) [i, v, true_]+write_boff_f32 a i v = ApplStat (a .^ "dv" .^ "setFloat32") [i, v, true_]+write_boff_f64 a i v = ApplStat (a .^ "dv" .^ "setFloat64") [i, v, true_]++read_boff_i8, read_boff_u8, read_boff_i16, read_boff_u16, read_boff_i32, read_boff_u32, read_boff_f32, read_boff_f64 :: JExpr -> JExpr -> JExpr+read_boff_i8  a i = read_i8 a i+read_boff_u8  a i = read_u8 a i+read_boff_i16 a i = ApplExpr (a .^ "dv" .^ "getInt16"  ) [i, true_]+read_boff_u16 a i = ApplExpr (a .^ "dv" .^ "getUint16" ) [i, true_]+read_boff_i32 a i = ApplExpr (a .^ "dv" .^ "getInt32"  ) [i, true_]+read_boff_u32 a i = ApplExpr (a .^ "dv" .^ "getUint32" ) [i, true_]+read_boff_f32 a i = ApplExpr (a .^ "dv" .^ "getFloat32") [i, true_]+read_boff_f64 a i = ApplExpr (a .^ "dv" .^ "getFloat64") [i, true_]++fetchOpByteArray :: (JExpr -> JExpr -> JExpr) -> JExpr -> JExpr -> JExpr -> JExpr -> JStat+fetchOpByteArray op tgt src i v = mconcat+  [ tgt |= read_i32 src i+  , write_i32 src i (op tgt v)+  ]++fetchOpAddr :: (JExpr -> JExpr -> JExpr) -> JExpr -> JExpr -> JExpr -> JExpr -> JStat+fetchOpAddr op tgt src i v = mconcat+  [ tgt |= read_boff_u32 src i+  , write_boff_u32 src i (op tgt v)+  ]++casOp+  :: (JExpr -> JExpr -> JExpr)          -- read+  -> (JExpr -> JExpr -> JExpr -> JStat) -- write+  -> JExpr                     -- target register  to store result+  -> JExpr                     -- source arrays+  -> JExpr                     -- index+  -> JExpr                     -- old value to compare+  -> JExpr                     -- new value to write+  -> JStat+casOp read write tgt src i old new = mconcat+  [ tgt |= read src i+  , ifS (tgt .===. old)+        (write src i new)+         mempty+  ]++--------------------------------------------------------------------------------+--                            Lifted Arrays+--------------------------------------------------------------------------------+-- | lifted arrays+cloneArray :: JExpr -> JExpr -> Maybe JExpr -> JExpr -> JStat+cloneArray tgt src mb_offset len = mconcat+  [ tgt |= ApplExpr (src .^ "slice") [start, end]+  , tgt .^ closureMeta_   |= zero_+  , tgt .^ "__ghcjsArray" |= true_+  ]+  where+    start = fromMaybe zero_ mb_offset+    end   = maybe len (Add len) mb_offset++newArray :: JExpr -> JExpr -> JExpr -> JStat+newArray tgt len elem =+    tgt |= app "h$newArray" [len, elem]++newByteArray :: JExpr -> JExpr -> JStat+newByteArray tgt len =+  tgt |= app "h$newByteArray" [len]++boundsChecked :: Bool  -- ^ Should we do bounds checking?+              -> JExpr -- ^ Array+              -> JExpr -- ^ Index+              -> JStat -- ^ Result+              -> JStat+boundsChecked False _ _ r = r+boundsChecked True  xs i r =+  ifS ((i .<. xs .^ "length") .&&. (i .>=. zero_))+    r+    (returnS $ app "h$exitProcess" [Int 134])++-- e|0 (32 bit signed integer truncation) required because of JS numbers. e|0+-- converts e to an Int32. Note that e|0 _is still a Double_ because JavaScript.+-- So (x|0) * (y|0) can still return values outside of the Int32 range. You have+-- been warned!+toI32 :: JExpr -> JExpr+toI32 e = BOr e zero_++-- e>>>0  (32 bit unsigned integer truncation)+-- required because of JS numbers. e>>>0 converts e to a Word32+-- so  (-2147483648)       >>> 0  = 2147483648+-- and ((-2147483648) >>>0) | 0   = -2147483648+toU32 :: JExpr -> JExpr+toU32 e = e .>>>. zero_++quotShortInt :: Int -> JExpr -> JExpr -> JExpr+quotShortInt bits x y = BAnd (signed x `Div` signed y) mask+  where+    signed z = (z .<<. shift) .>>. shift+    shift    = toJExpr (32 - bits)+    mask     = toJExpr (((2::Integer) ^ bits) - 1)++remShortInt :: Int -> JExpr -> JExpr -> JExpr+remShortInt bits x y = BAnd (signed x `Mod` signed y) mask+  where+    signed z = (z .<<. shift) .>>. shift+    shift    = toJExpr (32 - bits)+    mask     = toJExpr (((2::Integer) ^ bits) - 1)
+ compiler/GHC/StgToJS/Printer.hs view
@@ -0,0 +1,218 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MagicHash #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Printer+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+-- Stability   :  experimental+--+-- Custom prettyprinter for JS AST uses the JS PPr module for most of+-- the work+--+--+-----------------------------------------------------------------------------+module GHC.StgToJS.Printer+  ( pretty+  , ghcjsRenderJs+  , prettyBlock+  )+where++import GHC.Prelude+import GHC.Int+import GHC.Exts++import GHC.JS.Syntax+import GHC.JS.Ppr++import GHC.Utils.Ppr      as PP+import GHC.Data.FastString+import GHC.Types.Unique.Map++import Data.List (sortOn)+import Data.Char (isAlpha,isDigit,ord)+import qualified Data.ByteString.Short as SBS++pretty :: JStat -> Doc+pretty = jsToDocR ghcjsRenderJs++ghcjsRenderJs :: RenderJs+ghcjsRenderJs = defaultRenderJs+  { renderJsV = ghcjsRenderJsV+  , renderJsS = ghcjsRenderJsS+  , renderJsI = ghcjsRenderJsI+  }++hdd :: SBS.ShortByteString+hdd = SBS.pack (map (fromIntegral . ord) "h$$")++ghcjsRenderJsI :: RenderJs -> Ident -> Doc+ghcjsRenderJsI _ (TxtI fs)+  -- Fresh symbols are prefixed with "h$$". They aren't explicitly referred by+  -- name in user code, only in compiled code. Hence we can rename them if we do+  -- it consistently in all the linked code.+  --+  -- These symbols are usually very large because their name includes the+  -- unit-id, the module name, and some unique number. So we rename these+  -- symbols with a much shorter globally unique number.+  --+  -- Here we reuse their FastString unique for this purpose! Note that it only+  -- works if we pretty-print all the JS code linked together at once, which we+  -- currently do. GHCJS used to maintain a CompactorState to support+  -- incremental linking: it contained the mapping between original symbols and+  -- their renaming.+  | hdd `SBS.isPrefixOf` fastStringToShortByteString fs+  , u <- uniqueOfFS fs+  = text "h$$" <> hexDoc (fromIntegral u)+  | otherwise+  = ftext fs++-- | Render as an hexadecimal number in reversed order (because it's faster and we+-- don't care about the actual value).+hexDoc :: Word -> Doc+hexDoc 0 = char '0'+hexDoc v = text $ go v+  where+    sym (I# i) = C# (indexCharOffAddr# chars i)+    chars = "0123456789abcdef"#+    go = \case+      0 -> []+      n -> sym (fromIntegral (n .&. 0x0F))+           : sym (fromIntegral ((n .&. 0xF0) `shiftR` 4))+           : go (n `shiftR` 8)+++++-- attempt to resugar some of the common constructs+ghcjsRenderJsS :: RenderJs -> JStat -> Doc+ghcjsRenderJsS r (BlockStat xs) = prettyBlock r (flattenBlocks xs)+ghcjsRenderJsS r s              = renderJsS defaultRenderJs r s++-- don't quote keys in our object literals, so closure compiler works+ghcjsRenderJsV :: RenderJs -> JVal -> Doc+ghcjsRenderJsV r (JHash m)+  | isNullUniqMap m = text "{}"+  | otherwise       = braceNest . PP.fsep . punctuate comma .+                          map (\(x,y) -> quoteIfRequired x <> PP.colon <+> jsToDocR r y)+                          -- nonDetEltsUniqMap doesn't introduce non-determinism here because+                          -- we sort the elements lexically+                          . sortOn (LexicalFastString . fst) $ nonDetEltsUniqMap m+  where+    quoteIfRequired :: FastString -> Doc+    quoteIfRequired x+      | isUnquotedKey x' = text x'+      | otherwise        = PP.squotes (text x')+      where x' = unpackFS x++    isUnquotedKey :: String -> Bool+    isUnquotedKey x | null x        = False+                    | all isDigit x = True+                    | otherwise     = validFirstIdent (head x)+                                      && all validOtherIdent (tail x)+++    validFirstIdent c = c == '_' || c == '$' || isAlpha c+    validOtherIdent c = isAlpha c || isDigit c+ghcjsRenderJsV r v = renderJsV defaultRenderJs r v++prettyBlock :: RenderJs -> [JStat] -> Doc+prettyBlock r xs = vcat $ map addSemi (prettyBlock' r xs)++-- recognize common patterns in a block and convert them to more idiomatic/concise javascript+prettyBlock' :: RenderJs -> [JStat] -> [Doc]+-- return/...+prettyBlock' r ( x@(ReturnStat _)+               : xs+               )+      | not (null xs)+      = prettyBlock' r [x]+-- declare/assign+prettyBlock' r ( (DeclStat i Nothing)+               : (AssignStat (ValExpr (JVar i')) v)+               : xs+               )+      | i == i'+      = prettyBlock' r (DeclStat i (Just v) : xs)++-- resugar for loops with/without var declaration+prettyBlock' r ( (DeclStat i (Just v0))+               : (WhileStat False p (BlockStat bs))+               : xs+               )+     | not (null flat) && isForUpdStat (last flat)+     = mkFor r True i v0 p (last flat) (init flat) : prettyBlock' r xs+        where+          flat = flattenBlocks bs+prettyBlock' r ( (AssignStat (ValExpr (JVar i)) v0)+               : (WhileStat False p (BlockStat bs))+               : xs+               )+     | not (null flat) && isForUpdStat (last flat)+     = mkFor r False i v0 p (last flat) (init flat) : prettyBlock' r xs+        where+          flat = flattenBlocks bs++-- global function (does not preserve semantics but works for GHCJS)+prettyBlock' r ( (DeclStat i (Just (ValExpr (JFunc is b))))+               : xs+               )+      = (hangBrace (text "function" <+> jsToDocR r i <> parens (fsep . punctuate comma . map (jsToDocR r) $ is))+                             (jsToDocR r b)+                  ) : prettyBlock' r xs+-- modify/assign operators+prettyBlock' r ( (AssignStat (ValExpr (JVar i)) (InfixExpr AddOp (ValExpr (JVar i')) (ValExpr (JInt 1))))+               : xs+               )+      | i == i' = (text "++" <> jsToDocR r i) : prettyBlock' r xs+prettyBlock' r ( (AssignStat (ValExpr (JVar i)) (InfixExpr SubOp (ValExpr (JVar i')) (ValExpr (JInt 1))))+               : xs+               )+      | i == i' = (text "--" <> jsToDocR r i) : prettyBlock' r xs+prettyBlock' r ( (AssignStat (ValExpr (JVar i)) (InfixExpr AddOp (ValExpr (JVar i')) e))+               : xs+               )+      | i == i' = (jsToDocR r i <+> text "+=" <+> jsToDocR r e) : prettyBlock' r xs+prettyBlock' r ( (AssignStat (ValExpr (JVar i)) (InfixExpr SubOp (ValExpr (JVar i')) e))+               : xs+               )+      | i == i' = (jsToDocR r i <+> text "-=" <+> jsToDocR r e) : prettyBlock' r xs+++prettyBlock' r (x:xs) = jsToDocR r x : prettyBlock' r xs+prettyBlock' _ [] = []++-- build the for block+mkFor :: RenderJs -> Bool -> Ident -> JExpr -> JExpr -> JStat -> [JStat] -> Doc+mkFor r decl i v0 p s1 sb = hangBrace (text "for" <> forCond)+                                      (jsToDocR r $ BlockStat sb)+    where+      c0 | decl      = text "var" <+> jsToDocR r i <+> char '=' <+> jsToDocR r v0+         | otherwise =                jsToDocR r i <+> char '=' <+> jsToDocR r v0+      forCond = parens $ hcat $ interSemi+                            [ c0+                            , jsToDocR r p+                            , parens (jsToDocR r s1)+                            ]++-- check if a statement is suitable to be converted to something in the for(;;x) position+isForUpdStat :: JStat -> Bool+isForUpdStat UOpStat {}    = True+isForUpdStat AssignStat {} = True+isForUpdStat ApplStat {}   = True+isForUpdStat _             = False++interSemi :: [Doc] -> [Doc]+interSemi [] = [PP.empty]+interSemi [s] = [s]+interSemi (x:xs) = x <> text ";" : interSemi xs++addSemi :: Doc -> Doc+addSemi x = x <> text ";"
+ compiler/GHC/StgToJS/Profiling.hs view
@@ -0,0 +1,178 @@+{-# LANGUAGE OverloadedStrings #-}++module GHC.StgToJS.Profiling+  ( initCostCentres+  , emitCostCentreDecl+  , emitCostCentreStackDecl+  , enterCostCentreFun+  , enterCostCentreThunk+  , setCC+  , pushRestoreCCS+  , jCurrentCCS+  , jCafCCS+  , jSystemCCS+  , costCentreLbl+  , costCentreStackLbl+  , singletonCCSLbl+  , ccsVarJ+  -- * Predicates+  , profiling+  , ifProfiling+  , ifProfilingM+  -- * helpers+  , profStat+  )+where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Make++import GHC.StgToJS.Regs+import GHC.StgToJS.Types+import GHC.StgToJS.Symbols+import GHC.StgToJS.Monad++import GHC.Types.CostCentre++import GHC.Data.FastString+import GHC.Unit.Module+import GHC.Utils.Encoding+import GHC.Utils.Outputable+import GHC.Utils.Panic+import qualified Control.Monad.Trans.State.Strict as State++--------------------------------------------------------------------------------+-- Initialization++initCostCentres :: CollectedCCs -> G ()+initCostCentres (local_CCs, singleton_CCSs) = do+    mapM_ emitCostCentreDecl local_CCs+    mapM_ emitCostCentreStackDecl singleton_CCSs++emitCostCentreDecl :: CostCentre -> G ()+emitCostCentreDecl cc = do+  ccsLbl <- costCentreLbl cc+  let is_caf = isCafCC cc+      label  = costCentreUserName cc+      modl   = moduleNameString $ moduleName $ cc_mod cc+      loc    = renderWithContext defaultSDocContext (ppr (costCentreSrcSpan cc))+      js     = ccsLbl ||= UOpExpr NewOp (ApplExpr (var "h$CC")+                                                  [ toJExpr label+                                                  , toJExpr modl+                                                  , toJExpr loc+                                                  , toJExpr is_caf+                                                  ])+  emitGlobal js++emitCostCentreStackDecl :: CostCentreStack -> G ()+emitCostCentreStackDecl ccs =+    case maybeSingletonCCS ccs of+      Just cc -> do+        ccsLbl <- singletonCCSLbl cc+        ccLbl  <- costCentreLbl cc+        let js = ccsLbl ||= UOpExpr NewOp (ApplExpr (var "h$CCS") [null_, toJExpr ccLbl])+        emitGlobal js+      Nothing -> pprPanic "emitCostCentreStackDecl" (ppr ccs)++--------------------------------------------------------------------------------+-- Entering to cost-centres++enterCostCentreFun :: CostCentreStack -> JStat+enterCostCentreFun ccs+  | isCurrentCCS ccs = ApplStat (var "h$enterFunCCS") [jCurrentCCS, r1 .^ "cc"]+  | otherwise = mempty -- top-level function, nothing to do++enterCostCentreThunk :: JStat+enterCostCentreThunk = ApplStat (var "h$enterThunkCCS") [r1 .^ "cc"]++setCC :: CostCentre -> Bool -> Bool -> G JStat+setCC cc _tick True = do+  ccI@(TxtI _ccLbl) <- costCentreLbl cc+  addDependency $ OtherSymb (cc_mod cc)+                            (moduleGlobalSymbol $ cc_mod cc)+  return $ jCurrentCCS |= ApplExpr (var "h$pushCostCentre") [jCurrentCCS, toJExpr ccI]+setCC _cc _tick _push = return mempty++pushRestoreCCS :: JStat+pushRestoreCCS = ApplStat (var "h$pushRestoreCCS") []++--------------------------------------------------------------------------------+-- Some cost-centre stacks to be used in generator++jCurrentCCS :: JExpr+jCurrentCCS = var "h$currentThread" .^ "ccs"++jCafCCS :: JExpr+jCafCCS = var "h$CAF"++jSystemCCS :: JExpr+jSystemCCS = var "h$CCS_SYSTEM"+--------------------------------------------------------------------------------+-- Helpers for generating profiling related things++profiling :: G Bool+profiling = csProf <$> getSettings++ifProfiling :: Monoid m => m -> G m+ifProfiling m = do+    prof <- profiling+    return $ if prof then m else mempty++ifProfilingM :: Monoid m => G m -> G m+ifProfilingM m = do+    prof <- profiling+    if prof then m else return mempty++-- | If profiling is enabled, then use input JStat, else ignore+profStat :: StgToJSConfig -> JStat -> JStat+profStat cfg e = if csProf cfg then e else mempty+--------------------------------------------------------------------------------+-- Generating cost-centre and cost-centre stack variables++costCentreLbl' :: CostCentre -> G String+costCentreLbl' cc = do+  curModl <- State.gets gsModule+  let lbl = renderWithContext defaultSDocContext+              $ withPprStyle PprCode (ppr cc)+  return . ("h$"++) . zEncodeString $+    moduleNameColons (moduleName curModl) ++ "_" ++ if isCafCC cc then "CAF_ccs" else lbl++costCentreLbl :: CostCentre -> G Ident+costCentreLbl cc = TxtI . mkFastString <$> costCentreLbl' cc++costCentreStackLbl' :: CostCentreStack -> G (Maybe String)+costCentreStackLbl' ccs = do+  ifProfilingM f+  where+    f | isCurrentCCS ccs   = return $ Just "h$currentThread.ccs"+      | dontCareCCS == ccs = return $ Just "h$CCS_DONT_CARE"+      | otherwise          =+          case maybeSingletonCCS ccs of+            Just cc -> Just <$> singletonCCSLbl' cc+            Nothing -> pure Nothing++costCentreStackLbl :: CostCentreStack -> G (Maybe Ident)+costCentreStackLbl ccs = fmap (TxtI . mkFastString) <$> costCentreStackLbl' ccs++singletonCCSLbl' :: CostCentre -> G String+singletonCCSLbl' cc = do+    curModl <- State.gets gsModule+    ccLbl   <- costCentreLbl' cc+    let ccsLbl = ccLbl ++ "_ccs"+    return . zEncodeString $ mconcat+              [ moduleNameColons (moduleName curModl)+              , "_"+              , ccsLbl+              ]++singletonCCSLbl :: CostCentre -> G Ident+singletonCCSLbl cc = TxtI . mkFastString <$> singletonCCSLbl' cc++ccsVarJ :: CostCentreStack -> G (Maybe JExpr)+ccsVarJ ccs = do+  prof <- profiling+  if prof+    then fmap (ValExpr . JVar) <$> costCentreStackLbl ccs+    else pure Nothing
+ compiler/GHC/StgToJS/Regs.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE OverloadedStrings #-}++module GHC.StgToJS.Regs+  ( StgReg (..)+  , Special(..)+  , sp+  , stack+  , r1, r2, r3, r4+  , regsFromR1+  , regsFromR2+  , jsRegsFromR1+  , jsRegsFromR2+  , StgRet (..)+  , jsRegToInt+  , intToJSReg+  , jsReg+  , maxReg+  , minReg+  )+where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Make++import GHC.Data.FastString++import Data.Array+import Data.Char++-- | General purpose "registers"+--+-- The JS backend arbitrarily supports 128 registers+data StgReg+  = R1  | R2  | R3  | R4  | R5  | R6  | R7  | R8+  | R9  | R10 | R11 | R12 | R13 | R14 | R15 | R16+  | R17 | R18 | R19 | R20 | R21 | R22 | R23 | R24+  | R25 | R26 | R27 | R28 | R29 | R30 | R31 | R32+  | R33 | R34 | R35 | R36 | R37 | R38 | R39 | R40+  | R41 | R42 | R43 | R44 | R45 | R46 | R47 | R48+  | R49 | R50 | R51 | R52 | R53 | R54 | R55 | R56+  | R57 | R58 | R59 | R60 | R61 | R62 | R63 | R64+  | R65 | R66 | R67 | R68 | R69 | R70 | R71 | R72+  | R73 | R74 | R75 | R76 | R77 | R78 | R79 | R80+  | R81 | R82 | R83 | R84 | R85 | R86 | R87 | R88+  | R89 | R90 | R91 | R92 | R93 | R94 | R95 | R96+  | R97  | R98  | R99  | R100 | R101 | R102 | R103 | R104+  | R105 | R106 | R107 | R108 | R109 | R110 | R111 | R112+  | R113 | R114 | R115 | R116 | R117 | R118 | R119 | R120+  | R121 | R122 | R123 | R124 | R125 | R126 | R127 | R128+  deriving (Eq, Ord, Show, Enum, Bounded, Ix)++-- | Stack registers+data Special+  = Stack+  | Sp+  deriving (Show, Eq)++-- | Return registers+--+-- Extra results from foreign calls can be stored here (while first result is+-- directly returned)+data StgRet = Ret1 | Ret2 | Ret3 | Ret4 | Ret5 | Ret6 | Ret7 | Ret8 | Ret9 | Ret10+  deriving (Eq, Ord, Show, Enum, Bounded, Ix)++instance ToJExpr Special where+  toJExpr Stack  = var "h$stack"+  toJExpr Sp     = var "h$sp"++instance ToJExpr StgReg where+  toJExpr r = registers ! r++instance ToJExpr StgRet where+  toJExpr r = rets ! r++---------------------------------------------------+-- helpers+---------------------------------------------------++sp :: JExpr+sp = toJExpr Sp++stack :: JExpr+stack = toJExpr Stack++r1, r2, r3, r4 :: JExpr+r1 = toJExpr R1+r2 = toJExpr R2+r3 = toJExpr R3+r4 = toJExpr R4+++jsRegToInt :: StgReg -> Int+jsRegToInt = (+1) . fromEnum++intToJSReg :: Int -> StgReg+intToJSReg r = toEnum (r - 1)++jsReg :: Int -> JExpr+jsReg r = toJExpr (intToJSReg r)++maxReg :: Int+maxReg = jsRegToInt maxBound++minReg :: Int+minReg = jsRegToInt minBound++-- | List of registers, starting from R1+regsFromR1 :: [StgReg]+regsFromR1 = enumFrom R1++-- | List of registers, starting from R2+regsFromR2 :: [StgReg]+regsFromR2 = tail regsFromR1++-- | List of registers, starting from R1 as JExpr+jsRegsFromR1 :: [JExpr]+jsRegsFromR1 = fmap toJExpr regsFromR1++-- | List of registers, starting from R2 as JExpr+jsRegsFromR2 :: [JExpr]+jsRegsFromR2 = tail jsRegsFromR1++---------------------------------------------------+-- caches+---------------------------------------------------++-- cache JExpr representing StgReg+registers :: Array StgReg JExpr+registers = listArray (minBound, maxBound) (map regN regsFromR1)+  where+    regN r+      | fromEnum r < 32 = var . mkFastString . ("h$"++) . map toLower . show $ r+      | otherwise       = IdxExpr (var "h$regs")+                            (toJExpr ((fromEnum r) - 32))++-- cache JExpr representing StgRet+rets :: Array StgRet JExpr+rets = listArray (minBound, maxBound) (map retN (enumFrom Ret1))+  where+    retN = var . mkFastString . ("h$"++) . map toLower . show
+ compiler/GHC/StgToJS/Rts/Rts.hs view
@@ -0,0 +1,661 @@+{-# LANGUAGE OverloadedStrings #-}++{-# OPTIONS_GHC -O0 #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Rts.Rts+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+-- Top level driver of the JavaScript Backend RTS. This file is an+-- implementation of the JS RTS for the JS backend written as an EDSL in+-- Haskell. It assumes the existence of pre-generated JS functions, included as+-- js-sources in base. These functions are similarly assumed for non-inline+-- Primops, See 'GHC.StgToJS.Prim'. Most of the elements in this module are+-- constants in Haskell Land which define pieces of the JS RTS.+--+-----------------------------------------------------------------------------++module GHC.StgToJS.Rts.Rts where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Make+import GHC.JS.Transform++import GHC.StgToJS.Apply+import GHC.StgToJS.Closure+import GHC.StgToJS.Heap+import GHC.StgToJS.Printer+import GHC.StgToJS.Profiling+import GHC.StgToJS.Regs+import GHC.StgToJS.Types+import GHC.StgToJS.Stack++import GHC.Data.FastString+import GHC.Types.Unique.Map++import Data.Array+import Data.Monoid+import Data.Char (toLower, toUpper)+import qualified Data.Bits          as Bits++-- | The garbageCollector resets registers and result variables.+garbageCollector :: JStat+garbageCollector =+  mconcat [ TxtI "h$resetRegisters"  ||= jLam (mconcat $ map resetRegister [minBound..maxBound])+          , TxtI "h$resetResultVars" ||= jLam (mconcat $ map resetResultVar [minBound..maxBound])+          ]++-- | Reset the register 'r' in JS Land. Note that this "resets" by setting the+-- register to a dummy variable called "null", /not/ by setting to JS's nil+-- value.+resetRegister :: StgReg -> JStat+resetRegister r = toJExpr r |= null_++-- | Reset the return variable 'r' in JS Land. Note that this "resets" by+-- setting the register to a dummy variable called "null", /not/ by setting to+-- JS's nil value.+resetResultVar :: StgRet -> JStat+resetResultVar r = toJExpr r |= null_++-- | Define closures based on size, these functions are syntactic sugar, e.g., a+-- Haskell function which generates some useful JS. Each Closure constructor+-- follows the naming convention h$cN, where N is a natural number. For example,+-- h$c (with the nat omitted) is a JS Land Constructor for a closure in JS land+-- which has a single entry function 'f', and no fields; identical to h$c0. h$c1+-- is a JS Land Constructor for a closure with an entry function 'f', and a+-- /single/ field 'x1', 'Just foo' is an example of this kind of closure. h$c2+-- is a JS Land Constructor for a closure with an entry function and two data+-- fields: 'x1' and 'x2'. And so on. Note that this has JIT performance+-- implications; you should use h$c1, h$c2, h$c3, ... h$c24 instead of making+-- objects manually so layouts and fields can be changed more easily and so the+-- JIT can optimize better.+closureConstructors :: StgToJSConfig -> JStat+closureConstructors s = BlockStat+  [ declClsConstr "h$c" ["f"] $ Closure+      { clEntry  = var "f"+      , clField1 = null_+      , clField2 = null_+      , clMeta   = 0+      , clCC     = ccVal+      }+  , declClsConstr "h$c0" ["f"] $ Closure+      { clEntry  = var "f"+      , clField1 = null_+      , clField2 = null_+      , clMeta   = 0+      , clCC     = ccVal+      }+  , declClsConstr "h$c1" ["f", "x1"] $ Closure+      { clEntry  = var "f"+      , clField1 = var "x1"+      , clField2 = null_+      , clMeta   = 0+      , clCC     = ccVal+      }+  , declClsConstr "h$c2" ["f", "x1", "x2"] $ Closure+      { clEntry  = var "f"+      , clField1 = var "x1"+      , clField2 = var "x2"+      , clMeta   = 0+      , clCC     = ccVal+      }+  , mconcat (map mkClosureCon [3..24])+  , mconcat (map mkDataFill [1..24])+  ]+  where+    prof = csProf s+    (ccArg,ccVal)+      -- the cc argument happens to be named just like the cc field...+      | prof      = ([TxtI closureCC_], Just (var closureCC_))+      | otherwise = ([], Nothing)+    addCCArg as = map TxtI as ++ ccArg+    addCCArg' as = as ++ ccArg++    declClsConstr i as cl = TxtI i ||= ValExpr (JFunc (addCCArg as)+      ( jVar $ \x ->+          [ checkC+          , x |= newClosure cl+          , notifyAlloc x+          , traceAlloc x+          , returnS x+          ]+         ))++    traceAlloc x | csTraceRts s = appS "h$traceAlloc" [x]+                 | otherwise    = mempty++    notifyAlloc x | csDebugAlloc s = appS "h$debugAlloc_notifyAlloc" [x]+                  | otherwise      = mempty++    -- only JSVal can typically contain undefined or null+    -- although it's possible (and legal) to make other Haskell types+    -- to contain JS refs directly+    -- this can cause false positives here+    checkC :: JStat+    checkC | csAssertRts s =+      jVar $ \msg ->+      jwhenS (var "arguments" .! 0 .!==. jString "h$baseZCGHCziJSziPrimziJSVal_con_e")+                                  (loop 1 (.<. var "arguments" .^ "length")+                                          (\i ->+                                             mconcat [msg |= jString "warning: undefined or null in argument: "+                                                       + i+                                                       + jString " allocating closure: " + (var "arguments" .! 0 .^ "n")+                                                     , appS "h$log" [msg]+                                                     , jwhenS (var "console" .&&. (var "console" .^ "trace")) ((var "console" .^ "trace") `ApplStat` [msg])+                                                     , postIncrS i+                                                     ])++                                  )+           | otherwise = mempty++    -- h$d is never used for JSVal (since it's only for constructors with+    -- at least three fields, so we always warn here+    checkD | csAssertRts s =+                     loop 0 (.<. var "arguments" .^ "length")+                     (\i -> jwhenS ((var "arguments" .! i .===. null_)+                                    .||. (var "arguments" .! i .===. undefined_))+                            (jVar $ \msg ->+                                mconcat [ msg |= jString "warning: undefined or null in argument: " + i + jString " allocating fields"+                                        , jwhenS (var "console" .&&. (var "console" .^ "trace"))+                                                ((var "console" .^ "trace") `ApplStat` [msg])+                                        ]))++           | otherwise = mempty++    mkClosureCon :: Int -> JStat+    mkClosureCon n = funName ||= toJExpr fun+      where+        funName = TxtI $ mkFastString ("h$c" ++ show n)+        -- args are: f x1 x2 .. xn [cc]+        args   = TxtI "f" : addCCArg' (map (TxtI . mkFastString . ('x':) . show) [(1::Int)..n])+        fun    = JFunc args funBod+        -- x1 goes into closureField1. All the other args are bundled into an+        -- object in closureField2: { d1 = x2, d2 = x3, ... }+        --+        extra_args = ValExpr . JHash . listToUniqMap $ zip+                   (map (mkFastString . ('d':) . show) [(1::Int)..])+                   (map (toJExpr . TxtI . mkFastString . ('x':) . show) [2..n])++        funBod = jVar $ \x ->+            [ checkC+            , x |= newClosure Closure+               { clEntry  = var "f"+               , clField1 = var "x1"+               , clField2 = extra_args+               , clMeta   = 0+               , clCC     = ccVal+               }+            , notifyAlloc x+            , traceAlloc x+            , returnS x+            ]++    mkDataFill :: Int -> JStat+    mkDataFill n = funName ||= toJExpr fun+      where+        funName    = TxtI $ mkFastString ("h$d" ++ show n)+        ds         = map (mkFastString . ('d':) . show) [(1::Int)..n]+        extra_args = ValExpr . JHash . listToUniqMap . zip ds $ map (toJExpr . TxtI) ds+        fun        = JFunc (map TxtI ds) (checkD <> returnS extra_args)++-- | JS Payload to perform stack manipulation in the RTS+stackManip :: JStat+stackManip = mconcat (map mkPush [1..32]) <>+             mconcat (map mkPpush [1..255])+  where+    mkPush :: Int -> JStat+    mkPush n = let funName = TxtI $ mkFastString ("h$p" ++ show n)+                   as      = map (TxtI . mkFastString . ('x':) . show) [1..n]+                   fun     = JFunc as ((sp |= sp + toJExpr n)+                                       <> mconcat (zipWith (\i a -> stack .! (sp - toJExpr (n-i)) |= toJExpr a)+                                                   [1..] as))+               in funName ||= toJExpr fun++    -- partial pushes, based on bitmap, increases Sp by highest bit+    mkPpush :: Integer -> JStat+    mkPpush sig | sig Bits..&. (sig+1) == 0 = mempty -- already handled by h$p+    mkPpush sig = let funName = TxtI $ mkFastString ("h$pp" ++ show sig)+                      bits    = bitsIdx sig+                      n       = length bits+                      h       = last bits+                      args    = map (TxtI . mkFastString . ('x':) . show) [1..n]+                      fun     = JFunc args $+                        mconcat [ sp |= sp + toJExpr (h+1)+                                , mconcat (zipWith (\b a -> stack .! (sp - toJExpr (h-b)) |= toJExpr a) bits args)+                                ]+                   in funName ||= toJExpr fun++bitsIdx :: Integer -> [Int]+bitsIdx n | n < 0 = error "bitsIdx: negative"+          | otherwise = go n 0+  where+    go 0 _ = []+    go m b | Bits.testBit m b = b : go (Bits.clearBit m b) (b+1)+           | otherwise   = go (Bits.clearBit m b) (b+1)++bhLneStats :: StgToJSConfig -> JExpr -> JExpr -> JStat+bhLneStats _s p frameSize =+   jVar $ \v ->+            mconcat [ v |= stack .! p+                    , ifS v+                      ((sp |= sp - frameSize)+                       <> ifS (v .===. var "h$blackhole")+                                (returnS $ app "h$throw" [var "h$baseZCControlziExceptionziBasezinonTermination", false_])+                                (mconcat [r1 |= v+                                         , sp |= sp - frameSize+                                         , returnStack+                                         ]))+                      ((stack .! p |= var "h$blackhole") <> returnS null_)+                    ]+++-- | JS payload to declare the registers+declRegs :: JStat+declRegs =+  mconcat [ TxtI "h$regs" ||= toJExpr (JList [])+          , mconcat (map declReg (enumFromTo R1 R32))+          , regGettersSetters+          , loadRegs+          ]+    where+      declReg r = (decl . TxtI . mkFastString . ("h$"++) . map toLower . show) r+                  <> BlockStat [AssignStat (toJExpr r) (ValExpr (JInt 0))] -- [j| `r` = 0; |]++-- | JS payload to define getters and setters on the registers.+regGettersSetters :: JStat+regGettersSetters =+  mconcat [ TxtI "h$getReg" ||= jLam (\n   -> SwitchStat n getRegCases mempty)+          , TxtI "h$setReg" ||= jLam (\n v -> SwitchStat n (setRegCases v) mempty)+          ]+  where+    getRegCases =+      map (\r -> (toJExpr (jsRegToInt r) , returnS (toJExpr r))) regsFromR1+    setRegCases v =+      map (\r -> (toJExpr (jsRegToInt r), (toJExpr r |= toJExpr v) <> returnS undefined_)) regsFromR1++-- | JS payload that defines the functions to load each register+loadRegs :: JStat+loadRegs = mconcat $ map mkLoad [1..32]+  where+    mkLoad :: Int -> JStat+    mkLoad n = let args   = map (TxtI . mkFastString . ("x"++) . show) [1..n]+                   assign = zipWith (\a r -> toJExpr r |= toJExpr a)+                              args (reverse $ take n regsFromR1)+                   fname  = TxtI $ mkFastString ("h$l" ++ show n)+                   fun    = JFunc args (mconcat assign)+               in fname ||= toJExpr fun++-- | Assign registers R1 ... Rn in descending order, that is assign Rn first.+-- This function uses the 'assignRegs'' array to construct functions which set+-- the registers.+assignRegs :: StgToJSConfig -> [JExpr] -> JStat+assignRegs _ [] = mempty+assignRegs s xs+  | l <= 32 && not (csInlineLoadRegs s)+      = ApplStat (ValExpr (JVar $ assignRegs'!l)) (reverse xs)+  | otherwise = mconcat . reverse $+      zipWith (\r ex -> toJExpr r |= ex) (take l regsFromR1) xs+  where+    l = length xs++-- | JS payload which defines an array of function symbols that set N registers+-- from M parameters. For example, h$l2 compiles to:+-- @+--    function h$l4(x1, x2, x3, x4) {+--      h$r4 = x1;+--      h$r3 = x2;+--      h$r2 = x3;+--      h$r1 = x4;+--    };+-- @+assignRegs' :: Array Int Ident+assignRegs' = listArray (1,32) (map (TxtI . mkFastString . ("h$l"++) . show) [(1::Int)..32])++-- | JS payload to declare return variables.+declRets :: JStat+declRets = mconcat $ map (decl . TxtI . mkFastString . ("h$"++) . map toLower . show) (enumFrom Ret1)++-- | JS payload defining the types closures.+closureTypes :: JStat+closureTypes = mconcat (map mkClosureType (enumFromTo minBound maxBound)) <> closureTypeName+  where+    mkClosureType :: ClosureType -> JStat+    mkClosureType c = let s = TxtI . mkFastString $ "h$" ++ map toUpper (show c) ++ "_CLOSURE"+                      in  s ||= toJExpr c+    closureTypeName :: JStat+    closureTypeName =+      TxtI "h$closureTypeName" ||= jLam (\c ->+                                           mconcat (map (ifCT c) [minBound..maxBound])+                                          <> returnS (jString "InvalidClosureType"))++    ifCT :: JExpr -> ClosureType -> JStat+    ifCT arg ct = jwhenS (arg .===. toJExpr ct) (returnS (toJExpr (show ct)))++-- | JS payload declaring the RTS functions.+rtsDecls :: JStat+rtsDecls = jsSaturate (Just "h$RTSD") $+  mconcat [ TxtI "h$currentThread"   ||= null_                   -- thread state object for current thread+          , TxtI "h$stack"           ||= null_                   -- stack for the current thread+          , TxtI "h$sp"              ||= 0                       -- stack pointer for the current thread+          , TxtI "h$initStatic"      ||= toJExpr (JList [])      -- we need delayed initialization for static objects, push functions here to be initialized just before haskell runs+          , TxtI "h$staticThunks"    ||= toJExpr (jhFromList []) --  funcName -> heapidx map for srefs+          , TxtI "h$staticThunksArr" ||= toJExpr (JList [])      -- indices of updatable thunks in static heap+          , TxtI "h$CAFs"            ||= toJExpr (JList [])+          , TxtI "h$CAFsReset"       ||= toJExpr (JList [])+          -- stg registers+          , declRegs+          , declRets]++-- | print the embedded RTS to a String+rtsText :: StgToJSConfig -> String+rtsText = show . pretty . rts++-- | print the RTS declarations to a String.+rtsDeclsText :: String+rtsDeclsText = show . pretty $ rtsDecls++-- | Wrapper over the RTS to guarentee saturation, see 'GHC.JS.Transform'+rts :: StgToJSConfig -> JStat+rts = jsSaturate (Just "h$RTS") . rts'++-- | JS Payload which defines the embedded RTS.+rts' :: StgToJSConfig -> JStat+rts' s =+  mconcat [ closureConstructors s+          , garbageCollector+          , stackManip+          , TxtI "h$rts_traceForeign" ||= toJExpr (csTraceForeign s)+          , TxtI "h$rts_profiling"    ||= toJExpr (csProf s)+          , TxtI "h$ct_fun"        ||= toJExpr Fun+          , TxtI "h$ct_con"        ||= toJExpr Con+          , TxtI "h$ct_thunk"      ||= toJExpr Thunk+          , TxtI "h$ct_pap"        ||= toJExpr Pap+          , TxtI "h$ct_blackhole"  ||= toJExpr Blackhole+          , TxtI "h$ct_stackframe" ||= toJExpr StackFrame+          , TxtI "h$vt_ptr"    ||= toJExpr PtrV+          , TxtI "h$vt_void"   ||= toJExpr VoidV+          , TxtI "h$vt_double" ||= toJExpr IntV+          , TxtI "h$vt_long"   ||= toJExpr LongV+          , TxtI "h$vt_addr"   ||= toJExpr AddrV+          , TxtI "h$vt_rtsobj" ||= toJExpr RtsObjV+          , TxtI "h$vt_obj"    ||= toJExpr ObjV+          , TxtI "h$vt_arr"    ||= toJExpr ArrV+          , TxtI "h$bh"        ||= jLam (bhStats s True)+          , TxtI "h$bh_lne"    ||= jLam (\x frameSize -> bhLneStats s x frameSize)+          , closure (ClosureInfo (TxtI "h$blackhole") (CIRegs 0 []) "blackhole" (CILayoutUnknown 2) CIBlackhole mempty)+               (appS "throw" [jString "oops: entered black hole"])+          , closure (ClosureInfo (TxtI "h$blackholeTrap") (CIRegs 0 []) "blackhole" (CILayoutUnknown 2) CIThunk mempty)+               (appS "throw" [jString "oops: entered multiple times"])+          , closure (ClosureInfo (TxtI "h$done") (CIRegs 0 [PtrV]) "done" (CILayoutUnknown 0) CIStackFrame mempty)+               (appS "h$finishThread" [var "h$currentThread"] <> returnS (var "h$reschedule"))+          , closure (ClosureInfo (TxtI "h$doneMain_e") (CIRegs 0 [PtrV]) "doneMain" (CILayoutUnknown 0) CIStackFrame mempty)+               (returnS (var "h$doneMain"))+          , conClosure (TxtI "h$false_e") "GHC.Types.False" (CILayoutFixed 0 []) 1+          , conClosure (TxtI "h$true_e" ) "GHC.Types.True"  (CILayoutFixed 0 []) 2+          -- generic data constructor with 1 non-heapobj field+          , conClosure (TxtI "h$data1_e") "data1" (CILayoutFixed 1 [ObjV]) 1+          -- generic data constructor with 2 non-heapobj fields+          , conClosure (TxtI "h$data2_e") "data2" (CILayoutFixed 2 [ObjV,ObjV]) 1+          , closure (ClosureInfo (TxtI "h$noop_e") (CIRegs 1 [PtrV]) "no-op IO ()" (CILayoutFixed 0 []) (CIFun 1 0) mempty)+               (returnS (stack .! sp))+            <> (TxtI "h$noop" ||= ApplExpr (var "h$c0") (var "h$noop_e" : [jSystemCCS | csProf s]))+          , closure (ClosureInfo (TxtI "h$catch_e") (CIRegs 0 [PtrV]) "exception handler" (CILayoutFixed 2 [PtrV,IntV]) CIStackFrame mempty)+               (adjSpN' 3 <> returnS (stack .! sp))+          , closure (ClosureInfo (TxtI "h$dataToTag_e") (CIRegs 0 [PtrV]) "data to tag" (CILayoutFixed 0 []) CIStackFrame mempty)+                $ mconcat [ r1 |= if_ (r1 .===. true_) 1 (if_ (typeof r1 .===. jTyObject) (r1 .^ "f" .^ "a" - 1) 0)+                          , adjSpN' 1+                          , returnS (stack .! sp)+                          ]+          -- function application to one argument+          , closure (ClosureInfo (TxtI "h$ap1_e") (CIRegs 0 [PtrV]) "apply1" (CILayoutFixed 2 [PtrV, PtrV]) CIThunk mempty)+               (jVar $ \d1 d2 ->+                   mconcat [ d1 |= closureField1 r1+                           , d2 |= closureField2 r1+                           , appS "h$bh" []+                           , profStat s enterCostCentreThunk+                           , r1 |= d1+                           , r2 |= d2+                           , returnS (app "h$ap_1_1_fast" [])+                           ])+          -- function application to two arguments+          , closure (ClosureInfo (TxtI "h$ap2_e") (CIRegs 0 [PtrV]) "apply2" (CILayoutFixed 3 [PtrV, PtrV, PtrV]) CIThunk mempty)+               (jVar $ \d1 d2 d3 ->+                   mconcat [ d1 |= closureField1 r1+                           , d2 |= closureField2 r1 .^ "d1"+                           , d3 |= closureField2 r1 .^ "d2"+                           , appS "h$bh" []+                           , profStat s enterCostCentreThunk+                           , r1 |= d1+                           , r2 |= d2+                           , r3 |= d3+                           , returnS (app "h$ap_2_2_fast" [])+                           ])+          -- function application to three arguments+          , closure (ClosureInfo (TxtI "h$ap3_e") (CIRegs 0 [PtrV]) "apply3" (CILayoutFixed 4 [PtrV, PtrV, PtrV, PtrV]) CIThunk mempty)+               (jVar $ \d1 d2 d3 d4 ->+                   mconcat [ d1 |= closureField1 r1+                           , d2 |= closureField2 r1 .^ "d1"+                           , d3 |= closureField2 r1 .^ "d2"+                           , d4 |= closureField2 r1 .^ "d3"+                           , appS "h$bh" []+                           , r1 |= d1+                           , r2 |= d2+                           , r3 |= d3+                           , r4 |= d4+                           , returnS (app "h$ap_3_3_fast" [])+                           ])+          -- select first field+          , closure (ClosureInfo (TxtI "h$select1_e") (CIRegs 0 [PtrV]) "select1" (CILayoutFixed 1 [PtrV]) CIThunk mempty)+               (jVar $ \t ->+                   mconcat [ t |= closureField1 r1+                           , adjSp' 3+                           , stack .! (sp - 2) |= r1+                           , stack .! (sp - 1) |= var "h$upd_frame"+                           , stack .! sp |= var "h$select1_ret"+                           , closureEntry  r1 |= var "h$blackhole"+                           , closureField1 r1 |= var "h$currentThread"+                           , closureField2 r1 |= null_+                           , r1 |= t+                           , returnS (app "h$ap_0_0_fast" [])+                           ])+          , closure (ClosureInfo (TxtI "h$select1_ret") (CIRegs 0 [PtrV]) "select1ret" (CILayoutFixed 0 []) CIStackFrame mempty)+               ((r1 |= closureField1 r1)+                <> adjSpN' 1+                <> returnS (app "h$ap_0_0_fast" [])+               )+          -- select second field of a two-field constructor+          , closure (ClosureInfo (TxtI "h$select2_e") (CIRegs 0 [PtrV]) "select2" (CILayoutFixed 1 [PtrV]) CIThunk mempty)+               (jVar $ \t ->+                   mconcat [t |= closureField1 r1+                           , adjSp' 3+                           , stack .! (sp - 2) |= r1+                           , stack .! (sp - 1) |= var "h$upd_frame"+                           , stack .! sp |= var "h$select2_ret"+                           , closureEntry  r1 |= var "h$blackhole"+                           , closureField1 r1 |= var "h$currentThread"+                           , closureField2 r1 |= null_+                           , r1 |= t+                           , returnS (app "h$ap_0_0_fast" [])+                           ]+                  )+          , closure (ClosureInfo (TxtI "h$select2_ret") (CIRegs 0 [PtrV]) "select2ret" (CILayoutFixed 0 []) CIStackFrame mempty)+                        $ mconcat [ r1 |= closureField2 r1+                                  , adjSpN' 1+                                  , returnS (app "h$ap_0_0_fast" [])+                                  ]+          , closure (ClosureInfo (TxtI "h$keepAlive_e") (CIRegs 0 [PtrV]) "keepAlive" (CILayoutFixed 1 [PtrV]) CIStackFrame mempty)+                    (mconcat [ adjSpN' 2+                             , returnS (stack .! sp)+                             ]+                    )+          -- a thunk that just raises a synchronous exception+          , closure (ClosureInfo (TxtI "h$raise_e") (CIRegs 0 [PtrV]) "h$raise_e" (CILayoutFixed 0 []) CIThunk mempty)+               (returnS (app "h$throw" [closureField1 r1, false_]))+          , closure (ClosureInfo (TxtI "h$raiseAsync_e") (CIRegs 0 [PtrV]) "h$raiseAsync_e" (CILayoutFixed 0 []) CIThunk mempty)+               (returnS  (app "h$throw" [closureField1 r1, true_]))+          , closure (ClosureInfo (TxtI "h$raiseAsync_frame") (CIRegs 0 []) "h$raiseAsync_frame" (CILayoutFixed 1 []) CIStackFrame mempty)+               (jVar $ \ex ->+                   mconcat [ ex |= stack .! (sp - 1)+                           , adjSpN' 2+                           , returnS (app "h$throw" [ex, true_])+                           ])+          {- reduce result if it's a thunk, follow if it's an ind+             add this to the stack if you want the outermost result+             to always be reduced to whnf, and not an ind+          -}+          , closure (ClosureInfo (TxtI "h$reduce") (CIRegs 0 [PtrV]) "h$reduce" (CILayoutFixed 0 []) CIStackFrame mempty)+               (ifS (isThunk r1)+                    (returnS (r1 .^ "f"))+                    (adjSpN' 1 <> returnS (stack .! sp))+               )+          , rtsApply s+          , closureTypes+          , closure (ClosureInfo (TxtI "h$runio_e") (CIRegs 0 [PtrV]) "runio" (CILayoutFixed 1 [PtrV]) CIThunk mempty)+                        $ mconcat [ r1 |= closureField1 r1+                                  , stack .! PreInc sp |= var "h$ap_1_0"+                                  , returnS (var "h$ap_1_0")+                                  ]+          , closure (ClosureInfo (TxtI "h$flushStdout_e") (CIRegs 0 []) "flushStdout" (CILayoutFixed 0 []) CIThunk mempty)+                        $ mconcat [ r1 |= var "h$baseZCGHCziIOziHandlezihFlush"+                                  , r2 |= var "h$baseZCGHCziIOziHandleziFDzistdout"+                                  , returnS (app "h$ap_1_1_fast" [])+                                  ]+          , TxtI "h$flushStdout" ||= app "h$static_thunk" [var "h$flushStdout_e"]+          -- the scheduler pushes this frame when suspending a thread that+          -- has not called h$reschedule explicitly+          , closure (ClosureInfo (TxtI "h$restoreThread") (CIRegs 0 []) "restoreThread" CILayoutVariable CIStackFrame mempty)+                (jVar $ \f frameSize nregs ->+                    mconcat [f |= stack .! (sp - 2)+                            , frameSize |= stack .! (sp - 1)+                            , nregs |= frameSize - 3+                            , loop 1 (.<=. nregs)+                                     (\i -> appS "h$setReg" [i, stack .! (sp - 2 - i)] <> postIncrS i)+                            , sp |= sp - frameSize+                            , returnS f+                            ])+          -- return a closure in the stack frame to the next thing on the stack+          , closure (ClosureInfo (TxtI "h$return") (CIRegs 0 []) "return" (CILayoutFixed 1 [PtrV]) CIStackFrame mempty)+                ((r1 |= stack .! (sp - 1))+                 <> adjSpN' 2+                 <> returnS (stack .! sp))+          --  return a function in the stack frame for the next call+          , closure (ClosureInfo (TxtI "h$returnf") (CIRegs 0 [PtrV]) "returnf" (CILayoutFixed 1 [ObjV]) CIStackFrame mempty)+                (jVar $ \r ->+                    mconcat [ r |= stack .! (sp - 1)+                            , adjSpN' 2+                            , returnS r+                            ])+          -- return this function when the scheduler needs to come into action+          -- (yield, delay etc), returning thread needs to push all relevant+          -- registers to stack frame, thread will be resumed by calling the stack top+          , closure (ClosureInfo (TxtI "h$reschedule") (CIRegs 0 []) "reschedule" (CILayoutFixed 0 []) CIThunk mempty)+                (returnS $ var "h$reschedule")+          -- debug thing, insert on stack to dump current result, should be boxed+          , closure (ClosureInfo (TxtI "h$dumpRes") (CIRegs 0 [PtrV]) "dumpRes" (CILayoutFixed 1 [ObjV]) CIThunk mempty)+                (jVar $ \re ->+                    mconcat [ appS "h$log" [jString "h$dumpRes result: " + stack .! (sp-1)]+                            , appS "h$log" [r1]+                            , appS "h$log" [app "h$collectProps" [r1]]+                            , jwhenS ((r1 .^ "f") .&&. (r1 .^ "f" .^ "n"))+                                        (appS "h$log" [jString "name: " + r1 .^ "f" .^ "n"])+                            , jwhenS (ApplExpr (r1 .^ "hasOwnProperty") [jString closureField1_])+                                        (appS "h$log" [jString "d1: " + closureField1 r1])+                            , jwhenS (ApplExpr (r1 .^ "hasOwnProperty") [jString closureField2_])+                                        (appS "h$log" [jString "d2: " + closureField2 r1])+                            , jwhenS (r1 .^ "f") $ mconcat+                                [ re |= New (app "RegExp" [jString "([^\\n]+)\\n(.|\\n)*"])+                                , appS "h$log" [jString "function"+                                                + ApplExpr (ApplExpr ((jString "" + r1 .^ "f") .^ "substring") [0, 50] .^ "replace") [r1, jString "$1"]]+                                ]+                            , adjSpN' 2+                            , r1 |= null_+                            , returnS (stack .! sp)+                            ])+          , closure (ClosureInfo (TxtI "h$resume_e") (CIRegs 0 [PtrV]) "resume" (CILayoutFixed 0 []) CIThunk mempty)+                  (jVar $ \ss ->+                      mconcat [ss |= closureField1 r1+                              , updateThunk' s+                              , loop 0 (.<. ss .^ "length") (\i -> (stack .! (sp+1+i) |= ss .! i)+                                                                   <> postIncrS i)+                              , sp |= sp + ss .^ "length"+                              , r1 |= null_+                              , returnS (stack .! sp)+                              ])+          , closure (ClosureInfo (TxtI "h$unmaskFrame") (CIRegs 0 [PtrV]) "unmask" (CILayoutFixed 0 []) CIStackFrame mempty)+               ((var "h$currentThread" .^ "mask" |= 0)+                <> adjSpN' 1+                -- back to scheduler to give us async exception if pending+                <> ifS (var "h$currentThread" .^ "excep" .^ "length" .>. 0)+                    (push' s [r1, var "h$return"] <> returnS (var "h$reschedule"))+                    (returnS (stack .! sp)))+          , closure (ClosureInfo (TxtI "h$maskFrame") (CIRegs 0 [PtrV]) "mask" (CILayoutFixed 0 []) CIStackFrame mempty)+                ((var "h$currentThread" .^ "mask" |= 2)+                 <> adjSpN' 1+                 <> returnS (stack .! sp))+          , closure (ClosureInfo (TxtI "h$maskUnintFrame") (CIRegs 0 [PtrV]) "maskUnint" (CILayoutFixed 0 []) CIStackFrame mempty)+                ((var "h$currentThread" .^ "mask" |= 1)+                 <> adjSpN' 1+                 <> returnS (stack .! sp))+          , closure (ClosureInfo (TxtI "h$unboxFFIResult") (CIRegs 0 [PtrV]) "unboxFFI" (CILayoutFixed 0 []) CIStackFrame mempty)+               (jVar $ \d ->+                   mconcat [d |= closureField1 r1+                           , loop 0 (.<. d .^ "length") (\i -> appS "h$setReg" [i + 1, d .! i] <> postIncrS i)+                           , adjSpN' 1+                           , returnS (stack .! sp)+                           ])+          , closure (ClosureInfo (TxtI "h$unbox_e") (CIRegs 0 [PtrV]) "unboxed value" (CILayoutFixed 1 [DoubleV]) CIThunk mempty)+               ((r1 |= closureField1 r1) <> returnS (stack .! sp))+          , closure (ClosureInfo (TxtI "h$retryInterrupted") (CIRegs 0 [ObjV]) "retry interrupted operation" (CILayoutFixed 1 [ObjV]) CIStackFrame mempty)+               (jVar $ \a ->+                   mconcat [ a |= stack .! (sp - 1)+                           , adjSpN' 2+                           , returnS (ApplExpr (a .! 0 .^ "apply") [var "this", ApplExpr (a .^ "slice") [1]])+                           ])+          , closure (ClosureInfo (TxtI "h$atomically_e") (CIRegs 0 [PtrV]) "atomic operation" (CILayoutFixed 1 [PtrV]) CIStackFrame mempty)+               (ifS (app "h$stmValidateTransaction" [])+                    (appS "h$stmCommitTransaction" []+                     <> adjSpN' 2+                     <> returnS (stack .! sp))+                    (returnS (app "h$stmStartTransaction" [stack .! (sp - 1)])))++          , closure (ClosureInfo (TxtI "h$stmCatchRetry_e") (CIRegs 0 [PtrV]) "catch retry" (CILayoutFixed 1 [PtrV]) CIStackFrame mempty)+                        (adjSpN' 2+                         <> appS "h$stmCommitTransaction" []+                         <> returnS (stack .! sp))+          , closure (ClosureInfo (TxtI "h$catchStm_e") (CIRegs 0 [PtrV]) "STM catch" (CILayoutFixed 3 [ObjV,PtrV,ObjV]) CIStackFrame mempty)+                       (adjSpN' 4+                       <> appS "h$stmCommitTransaction" []+                       <> returnS (stack .! sp))+          , closure (ClosureInfo (TxtI "h$stmResumeRetry_e") (CIRegs 0 [PtrV]) "resume retry" (CILayoutFixed 0 []) CIStackFrame mempty)+                        (jVar $ \blocked ->+                            mconcat [ jwhenS (stack .! (sp - 2) .!==. var "h$atomically_e")+                                                 (appS "throw" [jString "h$stmResumeRetry_e: unexpected value on stack"])+                                    , blocked |= stack .! (sp - 1)+                                    , adjSpN' 2+                                    , appS "h$stmRemoveBlockedThread" [blocked, var "h$currentThread"]+                                    , returnS (app "h$stmStartTransaction" [stack .! (sp - 1)])+                                    ])+          , closure (ClosureInfo (TxtI "h$lazy_e") (CIRegs 0 [PtrV]) "generic lazy value" (CILayoutFixed 0 []) CIThunk mempty)+                        (jVar $ \x ->+                            mconcat [x |= ApplExpr (closureField1 r1) []+                                    , appS "h$bh" []+                                    , profStat s enterCostCentreThunk+                                    , r1 |= x+                                    , returnS (stack .! sp)+                                    ])+          -- Top-level statements to generate only in profiling mode+          , profStat s (closure (ClosureInfo (TxtI "h$setCcs_e") (CIRegs 0 [PtrV]) "set cost centre stack" (CILayoutFixed 1 [ObjV]) CIStackFrame mempty)+                        (appS "h$restoreCCS" [ stack .! (sp - 1)]+                         <> adjSpN' 2+                         <> returnS (stack .! sp)))+          ]
+ compiler/GHC/StgToJS/Rts/Types.hs view
@@ -0,0 +1,78 @@+{-# LANGUAGE CPP,+             FlexibleInstances,+             OverloadedStrings #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Rts.Apply+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+-- Types and utility functions used in the JS RTS.+-----------------------------------------------------------------------------++module GHC.StgToJS.Rts.Types where++import GHC.Prelude++import GHC.JS.Make+import GHC.JS.Syntax+import GHC.StgToJS.Regs+import GHC.StgToJS.Types++--------------------------------------------------------------------------------+-- Syntactic Sugar for some Utilities we want in JS land+--------------------------------------------------------------------------------++-- | Syntactic sugar, i.e., a Haskell function which generates useful JS code.+-- Given a @JExpr@, 'ex', inject a trace statement on 'ex' in the compiled JS+-- program+traceRts :: StgToJSConfig -> JExpr -> JStat+traceRts s ex | (csTraceRts s)  = appS "h$log" [ex]+              | otherwise       = mempty++-- | Syntactic sugar. Given a @JExpr@, 'ex' which is assumed to be a predicate,+-- and a message 'm', assert that 'not ex' is True, if not throw an exception in+-- JS land with message 'm'.+assertRts :: ToJExpr a => StgToJSConfig -> JExpr -> a -> JStat+assertRts s ex m | csAssertRts s = jwhenS (UOpExpr NotOp ex) (appS "throw" [toJExpr m])+                 | otherwise     = mempty++-- | name of the closure 'c'+clName :: JExpr -> JExpr+clName c = c .^ "n"++-- | Type name of the closure 'c'+clTypeName :: JExpr -> JExpr+clTypeName c = app "h$closureTypeName" [c .^ "t"]++-- number of  arguments (arity & 0xff = arguments, arity >> 8 = number of registers)+stackFrameSize :: JExpr -- ^ assign frame size to this+               -> JExpr -- ^ stack frame header function+               -> JStat -- ^ size of the frame, including header+stackFrameSize tgt f =+  ifS (f .===. var "h$ap_gen") -- h$ap_gen is special+      (tgt |= (stack .! (sp - 1) .>>. 8) + 2)+      (jVar (\tag ->+               mconcat+               [tag |= f .^ "size"+               , ifS (tag .<. 0)              -- if tag is less than 0+                 (tgt |= stack .! (sp - 1))   -- set target to stack pointer - 1+                 (tgt |= mask8 tag + 1)       -- else set to mask'd tag + 1+               ]+        ))++--------------------------------------------------------------------------------+-- Register utilities+--------------------------------------------------------------------------------++-- | Perform the computation 'f', on the range of registers bounded by 'start'+-- and 'end'.+withRegs :: StgReg -> StgReg -> (StgReg -> JStat) -> JStat+withRegs start end f = mconcat $ fmap f [start..end]
+ compiler/GHC/StgToJS/Sinker.hs view
@@ -0,0 +1,180 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE LambdaCase #-}++module GHC.StgToJS.Sinker (sinkPgm) where++import GHC.Prelude+import GHC.Types.Unique.Set+import GHC.Types.Unique.FM+import GHC.Types.Var.Set+import GHC.Stg.Syntax+import GHC.Types.Id+import GHC.Types.Name+import GHC.Unit.Module+import GHC.Types.Literal+import GHC.Data.Graph.Directed++import GHC.StgToJS.CoreUtils++import Data.Char+import Data.Either+import Data.List (partition)+import Data.Maybe+++-- | Unfloat some top-level unexported things+--+-- GHC floats constants to the top level. This is fine in native code, but with JS+-- they occupy some global variable name. We can unfloat some unexported things:+--+-- - global constructors, as long as they're referenced only once by another global+--      constructor and are not in a recursive binding group+-- - literals (small literals may also be sunk if they are used more than once)+sinkPgm :: Module+        -> [CgStgTopBinding]+        -> (UniqFM Id CgStgExpr, [CgStgTopBinding])+sinkPgm m pgm = (sunk, map StgTopLifted pgm'' ++ stringLits)+  where+    selectLifted (StgTopLifted b) = Left b+    selectLifted x                = Right x+    (pgm', stringLits) = partitionEithers (map selectLifted pgm)+    (sunk, pgm'')      = sinkPgm' m pgm'++sinkPgm'+  :: Module+       -- ^ the module, since we treat definitions from the current module+       -- differently+  -> [CgStgBinding]+       -- ^ the bindings+  -> (UniqFM Id CgStgExpr, [CgStgBinding])+       -- ^ a map with sunken replacements for nodes, for where the replacement+       -- does not fit in the 'StgBinding' AST and the new bindings+sinkPgm' m pgm =+  let usedOnce = collectUsedOnce pgm+      sinkables = listToUFM $+          concatMap alwaysSinkable pgm +++          filter ((`elementOfUniqSet` usedOnce) . fst) (concatMap (onceSinkable m) pgm)+      isSunkBind (StgNonRec b _e) | elemUFM b sinkables = True+      isSunkBind _                                      = False+  in (sinkables, filter (not . isSunkBind) $ topSortDecls m pgm)++-- | always sinkable, values that may be duplicated in the generated code (e.g.+-- small literals)+alwaysSinkable :: CgStgBinding -> [(Id, CgStgExpr)]+alwaysSinkable (StgRec {})       = []+alwaysSinkable (StgNonRec b rhs) = case rhs of+  StgRhsClosure _ _ _ _ e@(StgLit l)+    | isSmallSinkableLit l+    , isLocal b+    -> [(b,e)]+  StgRhsCon _ccs dc cnum _ticks as@[StgLitArg l]+    | isSmallSinkableLit l+    , isLocal b+    , isUnboxableCon dc+    -> [(b,StgConApp dc cnum as [])]+  _ -> []++isSmallSinkableLit :: Literal -> Bool+isSmallSinkableLit (LitChar c)     = ord c < 100000+isSmallSinkableLit (LitNumber _ i) = abs i < 100000+isSmallSinkableLit _               = False+++-- | once sinkable: may be sunk, but duplication is not ok+onceSinkable :: Module -> CgStgBinding -> [(Id, CgStgExpr)]+onceSinkable _m (StgNonRec b rhs)+  | Just e <- getSinkable rhs+  , isLocal b = [(b,e)]+  where+    getSinkable = \case+      StgRhsCon _ccs dc cnum _ticks args -> Just (StgConApp dc cnum args [])+      StgRhsClosure _ _ _ _ e@(StgLit{}) -> Just e+      _                                  -> Nothing+onceSinkable _ _ = []++-- | collect all idents used only once in an argument at the top level+--   and never anywhere else+collectUsedOnce :: [CgStgBinding] -> IdSet+collectUsedOnce binds = intersectUniqSets (usedOnce args) (usedOnce top_args)+  where+    top_args = concatMap collectArgsTop binds+    args     = concatMap collectArgs    binds+    usedOnce = fst . foldr g (emptyUniqSet, emptyUniqSet)+    g i t@(once, mult)+      | i `elementOfUniqSet` mult = t+      | i `elementOfUniqSet` once+        = (delOneFromUniqSet once i, addOneToUniqSet mult i)+      | otherwise = (addOneToUniqSet once i, mult)++-- | fold over all id in StgArg used at the top level in an StgRhsCon+collectArgsTop :: CgStgBinding -> [Id]+collectArgsTop = \case+  StgNonRec _b r -> collectArgsTopRhs r+  StgRec bs      -> concatMap (collectArgsTopRhs . snd) bs++collectArgsTopRhs :: CgStgRhs -> [Id]+collectArgsTopRhs = \case+  StgRhsCon _ccs _dc _mu _ticks args -> concatMap collectArgsA args+  StgRhsClosure {}                   -> []++-- | fold over all Id in StgArg in the AST+collectArgs :: CgStgBinding -> [Id]+collectArgs = \case+  StgNonRec _b r -> collectArgsR r+  StgRec bs      -> concatMap (collectArgsR . snd) bs++collectArgsR :: CgStgRhs -> [Id]+collectArgsR = \case+  StgRhsClosure _x0 _x1 _x2 _x3 e     -> collectArgsE e+  StgRhsCon _ccs _con _mu _ticks args -> concatMap collectArgsA args++collectArgsAlt :: CgStgAlt -> [Id]+collectArgsAlt alt = collectArgsE (alt_rhs alt)++collectArgsE :: CgStgExpr -> [Id]+collectArgsE = \case+  StgApp x args+    -> x : concatMap collectArgsA args+  StgConApp _con _mn args _ts+    -> concatMap collectArgsA args+  StgOpApp _x args _t+    -> concatMap collectArgsA args+  StgCase e _b _a alts+    -> collectArgsE e ++ concatMap collectArgsAlt alts+  StgLet _x b e+    -> collectArgs b ++ collectArgsE e+  StgLetNoEscape _x b e+    -> collectArgs b ++ collectArgsE e+  StgTick _i e+    -> collectArgsE e+  StgLit _+    -> []++collectArgsA :: StgArg -> [Id]+collectArgsA = \case+  StgVarArg i -> [i]+  StgLitArg _ -> []++isLocal :: Id -> Bool+isLocal i = isNothing (nameModule_maybe . idName $ i) && not (isExportedId i)++-- | since we have sequential initialization, topsort the non-recursive+-- constructor bindings+topSortDecls :: Module -> [CgStgBinding] -> [CgStgBinding]+topSortDecls _m binds = rest ++ nr'+  where+    (nr, rest) = partition isNonRec binds+    isNonRec StgNonRec{} = True+    isNonRec _           = False+    vs   = map getV nr+    keys = mkUniqSet (map node_key vs)+    getV e@(StgNonRec b _) = DigraphNode e b []+    getV _                 = error "topSortDecls: getV, unexpected binding"+    collectDeps (StgNonRec b (StgRhsCon _cc _dc _cnum _ticks args)) =+      [ (i, b) | StgVarArg i <- args, i `elementOfUniqSet` keys ]+    collectDeps _ = []+    g = graphFromVerticesAndAdjacency vs (concatMap collectDeps nr)+    nr' | (not . null) [()| CyclicSCC _ <- stronglyConnCompG g]+            = error "topSortDecls: unexpected cycle"+        | otherwise = map node_payload (topologicalSortG g)
+ compiler/GHC/StgToJS/Stack.hs view
@@ -0,0 +1,373 @@+{-# LANGUAGE OverloadedStrings #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.JS.Stack+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+-- Utilities and wrappers for Stack manipulation in JS Land.+--+-- In general, functions suffixed with a tick do the actual work, functions+-- suffixed with an "I" are identical to the non-I versions but work on 'Ident's+--+-- The stack in JS land is held in the special JS array 'h$stack' and the stack+-- pointer is held in 'h$sp'. The top of the stack thus exists at+-- 'h$stack[h$sp]'. h$stack[h$sp + i] where i > 0, moves deeper into the stack+-- into older entries, whereas h$stack[h$sp - i] moves towards the top of the+-- stack.+--+-- The stack layout algorithm is slightly peculiar. It makes an effort to+-- remember recently popped things so that if these values need to be pushed+-- then they can be quickly. The implementation for this is storing these values+-- above the stack pointer, and the pushing will skip slots that we know we will+-- use and fill in slots marked as unknown. Thus, you may find that our push and+-- pop functions do some non-traditional stack manipulation such as adding slots+-- in pop or removing slots in push.+-----------------------------------------------------------------------------++module GHC.StgToJS.Stack+  ( resetSlots+  , isolateSlots+  , setSlots+  , getSlots+  , addSlots+  , dropSlots+  , addUnknownSlots+  , push+  , push'+  , adjSpN+  , adjSpN'+  , adjSp'+  , adjSp+  , pushNN+  , pushNN'+  , pushN'+  , pushN+  , pushOptimized'+  , pushOptimized+  , pushLneFrame+  , popN+  , popSkip+  , popSkipI+  , loadSkip+  -- * Thunk update+  , updateThunk+  , updateThunk'+  , bhStats+  )+where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Make++import GHC.StgToJS.Types+import GHC.StgToJS.Monad+import GHC.StgToJS.Ids+import GHC.StgToJS.ExprCtx+import GHC.StgToJS.Heap+import GHC.StgToJS.Regs++import GHC.Types.Id+import GHC.Utils.Misc+import GHC.Data.FastString++import qualified Data.Bits as Bits+import qualified Data.List as L+import qualified Control.Monad.Trans.State.Strict as State+import Data.Array+import Data.Monoid+import Control.Monad++-- | Run the action, 'm', with no stack info+resetSlots :: G a -> G a+resetSlots m = do+  s <- getSlots+  d <- getStackDepth+  setSlots []+  a <- m+  setSlots s+  setStackDepth d+  return a++-- | run the action, 'm', with current stack info, but don't let modifications+-- propagate+isolateSlots :: G a -> G a+isolateSlots m = do+  s <- getSlots+  d <- getStackDepth+  a <- m+  setSlots s+  setStackDepth d+  pure a++-- | Set stack depth+setStackDepth :: Int -> G ()+setStackDepth d = modifyGroup (\s -> s { ggsStackDepth = d})++-- | Get stack depth+getStackDepth :: G Int+getStackDepth = State.gets (ggsStackDepth . gsGroup)++-- | Modify stack depth+modifyStackDepth :: (Int -> Int) -> G ()+modifyStackDepth f = modifyGroup (\s -> s { ggsStackDepth = f (ggsStackDepth s) })++-- | overwrite our stack knowledge+setSlots :: [StackSlot] -> G ()+setSlots xs = modifyGroup (\g -> g { ggsStack = xs})++-- | retrieve our current stack knowledge+getSlots :: G [StackSlot]+getSlots = State.gets (ggsStack . gsGroup)++-- | Modify stack slots+modifySlots :: ([StackSlot] -> [StackSlot]) -> G ()+modifySlots f = modifyGroup (\g -> g { ggsStack = f (ggsStack g)})++-- | add `n` unknown slots to our stack knowledge+addUnknownSlots :: Int -> G ()+addUnknownSlots n = addSlots (replicate n SlotUnknown)++-- | add knowledge about the stack slots+addSlots :: [StackSlot] -> G ()+addSlots xs = do+  s <- getSlots+  setSlots (xs ++ s)++-- | drop 'n' slots from our stack knowledge+dropSlots :: Int -> G ()+dropSlots n = modifySlots (drop n)++push :: [JExpr] -> G JStat+push xs = do+  dropSlots (length xs)+  modifyStackDepth (+ (length xs))+  flip push' xs <$> getSettings++push' :: StgToJSConfig -> [JExpr] -> JStat+push' _ [] = mempty+push' cs xs+   | csInlinePush cs || l > 32 || l < 2 = adjSp' l <> mconcat items+   | otherwise                          = ApplStat (toJExpr $ pushN ! l) xs+  where+    items = zipWith f [(1::Int)..] xs+    offset i | i == l    = sp+             | otherwise = InfixExpr SubOp sp (toJExpr (l - i))+    l = length xs+    f i e = AssignStat ((IdxExpr stack) (toJExpr (offset i))) (toJExpr e)+++-- | Grow the stack pointer by 'n' without modifying the stack depth. The stack+-- is just a JS array so we add to grow (instead of the traditional subtract)+adjSp' :: Int -> JStat+adjSp' 0 = mempty+adjSp' n = sp |= InfixExpr AddOp sp (toJExpr n)++-- | Shrink the stack pointer by 'n'. The stack grows downward so substract+adjSpN' :: Int -> JStat+adjSpN' 0 = mempty+adjSpN' n = sp |= InfixExpr SubOp sp (toJExpr n)++-- | Wrapper which adjusts the stack pointer /and/ modifies the stack depth+-- tracked in 'G'. See also 'adjSp'' which actually does the stack pointer+-- manipulation.+adjSp :: Int -> G JStat+adjSp 0 = return mempty+adjSp n = do+  -- grow depth by n+  modifyStackDepth (+n)+  return (adjSp' n)++-- | Shrink the stack and stack pointer. NB: This function is unsafe when the+-- input 'n', is negative. This function wraps around 'adjSpN' which actually+-- performs the work.+adjSpN :: Int -> G JStat+adjSpN 0 = return mempty+adjSpN n = do+  modifyStackDepth (\x -> x - n)+  return (adjSpN' n)++-- | A constant array that holds global function symbols which do N pushes onto+-- the stack. For example:+-- @+-- function h$p1(x1) {+--   ++h$sp;+--   h$stack[(h$sp - 0)] = x1;+-- };+-- function h$p2(x1, x2) {+--   h$sp += 2;+--   h$stack[(h$sp - 1)] = x1;+--   h$stack[(h$sp - 0)] = x2;+-- };+-- @+--+-- and so on up to 32.+pushN :: Array Int Ident+pushN = listArray (1,32) $ map (TxtI . mkFastString . ("h$p"++) . show) [(1::Int)..32]++-- | Convert all function symbols in 'pushN' to global top-level functions. This+-- is a hack which converts the function symbols to variables. This hack is+-- caught in 'GHC.StgToJS.Printer.prettyBlock'' to turn these into global+-- functions.+pushN' :: Array Int JExpr+pushN' = fmap (ValExpr . JVar) pushN++-- | Partial Push functions. Like 'pushN' except these push functions skip+-- slots. For example,+-- @+-- function h$pp33(x1, x2) {+--   h$sp += 6;+--   h$stack[(h$sp - 5)] = x1;+--   h$stack[(h$sp - 0)] = x2;+-- };+-- @+--+-- The 33rd entry skips slots 1-4 to bind the top of the stack and the 6th+-- slot. See 'pushOptimized' and 'pushOptimized'' for use cases.+pushNN :: Array Integer Ident+pushNN = listArray (1,255) $ map (TxtI . mkFastString . ("h$pp"++) . show) [(1::Int)..255]++-- | Like 'pushN'' but for the partial push functions+pushNN' :: Array Integer JExpr+pushNN' = fmap (ValExpr . JVar) pushNN++pushOptimized' :: [(Id,Int)] -> G JStat+pushOptimized' xs = do+  slots  <- getSlots+  pushOptimized =<< (zipWithM f xs (slots++repeat SlotUnknown))+  where+    f (i1,n1) xs2 = do+      xs <- varsForId i1+      let !id_n1 = xs !! (n1-1)++      case xs2 of+        SlotId i2 n2 -> pure (id_n1,i1==i2&&n1==n2)+        _            -> pure (id_n1,False)++-- | optimized push that reuses existing values on stack automatically chooses+-- an optimized partial push (h$ppN) function when possible.+pushOptimized :: [(JExpr,Bool)] -- ^ contents of the slots, True if same value is already there+              -> G JStat+pushOptimized [] = return mempty+pushOptimized xs = do+  dropSlots l+  modifyStackDepth (+ length xs)+  go .  csInlinePush <$> getSettings+  where+    go True = inlinePush+    go _+     | all snd xs                  = adjSp' l+     | all (not.snd) xs && l <= 32 =+        ApplStat (pushN' ! l) (map fst xs)+     | l <= 8 && not (snd $ last xs) =+        ApplStat (pushNN' ! sig) [ e | (e,False) <- xs ]+     | otherwise = inlinePush+    l   = length xs+    sig :: Integer+    sig = L.foldl1' (Bits..|.) $ zipWith (\(_e,b) i -> if not b then Bits.bit i else 0) xs [0..]+    inlinePush = adjSp' l <> mconcat (zipWith pushSlot [1..] xs)+    pushSlot i (ex, False) = IdxExpr stack (offset i) |= ex+    pushSlot _ _           = mempty+    offset i | i == l    = sp+             | otherwise = InfixExpr SubOp sp (toJExpr (l - i))++-- | push a let-no-escape frame onto the stack+pushLneFrame :: HasDebugCallStack => Int -> ExprCtx -> G JStat+pushLneFrame size ctx =+  let ctx' = ctxLneShrinkStack ctx size+  in pushOptimized' (ctxLneFrameVars ctx')++-- | Pop things, don't update the stack knowledge in 'G'+popSkip :: Int      -- ^ number of slots to skip+         -> [JExpr] -- ^ assign stack slot values to these+         -> JStat+popSkip 0 []  = mempty+popSkip n []  = adjSpN' n+popSkip n tgt = loadSkip n tgt <> adjSpN' (length tgt + n)++-- | Load 'length (xs :: [JExpr])' things from the stack at offset 'n :: Int'.+-- This function does no stack pointer manipulation, it merely indexes into the+-- stack and loads payloads into 'xs'.+loadSkip :: Int -> [JExpr] -> JStat+loadSkip = loadSkipFrom sp+  where+    loadSkipFrom :: JExpr -> Int -> [JExpr] -> JStat+    loadSkipFrom fr n xs = mconcat items+      where+        items = reverse $ zipWith f [(0::Int)..] (reverse xs)+        -- helper to generate sp - n offset to index with+        offset 0 = fr+        offset n = InfixExpr SubOp fr  (toJExpr n)+        -- helper to load stack .! i into ex, e.g., ex = stack[i]+        f i ex   = ex |= IdxExpr stack (toJExpr (offset (i+n)))+++-- | Pop but preserve the first N slots+popSkipI :: Int -> [(Ident,StackSlot)] -> G JStat+popSkipI 0 [] = pure mempty+popSkipI n [] = popN n+popSkipI n xs = do+  -- add N unknown slots+  addUnknownSlots n+  -- now add the slots from xs, after this line the stack should look like+  -- [xs] ++ [Unknown...] ++ old_stack+  addSlots (map snd xs)+  -- move stack pointer into the stack by (length xs + n), basically resetting+  -- the stack pointer+  a <- adjSpN (length xs + n)+  -- now load skipping first N slots+  return (loadSkipI n (map fst xs) <> a)++-- | Just like 'loadSkip' but operate on 'Ident's rather than 'JExpr'+loadSkipI :: Int -> [Ident] -> JStat+loadSkipI = loadSkipIFrom sp+  where loadSkipIFrom :: JExpr -> Int -> [Ident] -> JStat+        loadSkipIFrom fr n xs = mconcat items+          where+            items = reverse $ zipWith f [(0::Int)..] (reverse xs)+            offset 0 = fr+            offset n = InfixExpr SubOp fr (toJExpr n)+            f i ex   = ex ||= IdxExpr stack (toJExpr (offset (i+n)))++-- | Blindly pop N slots+popN :: Int -> G JStat+popN n = addUnknownSlots n >> adjSpN n++-- | Generate statements to update the current node with a blackhole+bhStats :: StgToJSConfig -> Bool -> JStat+bhStats s pushUpd = mconcat+  [ if pushUpd then push' s [r1, var "h$upd_frame"] else mempty+  , toJExpr R1 .^ closureEntry_  |= var "h$blackhole"+  , toJExpr R1 .^ closureField1_ |= var "h$currentThread"+  , toJExpr R1 .^ closureField2_ |= null_ -- will be filled with waiters array+  ]++-- | Wrapper around 'updateThunk'', performs the stack manipulation before+-- updating the Thunk.+updateThunk :: G JStat+updateThunk = do+  settings <- getSettings+  -- update frame size+  let adjPushStack :: Int -> G ()+      adjPushStack n = do modifyStackDepth (+n)+                          dropSlots n+  adjPushStack 2+  return $ (updateThunk' settings)++-- | Update a thunk by checking 'StgToJSConfig'. If the config inlines black+-- holes then update inline, else make an explicit call to the black hole+-- handler.+updateThunk' :: StgToJSConfig -> JStat+updateThunk' settings =+  if csInlineBlackhole settings+    then bhStats settings True+    else ApplStat (var "h$bh") []
+ compiler/GHC/StgToJS/StaticPtr.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE OverloadedStrings #-}++module GHC.StgToJS.StaticPtr+  ( initStaticPtrs+  )+where++import GHC.Prelude+import GHC.Linker.Types (SptEntry(..))+import GHC.Fingerprint.Type+import GHC.Types.Literal++import GHC.JS.Syntax+import GHC.JS.Make++import GHC.StgToJS.Types+import GHC.StgToJS.Literal+import GHC.StgToJS.Ids++initStaticPtrs :: [SptEntry] -> G JStat+initStaticPtrs ptrs = mconcat <$> mapM initStatic ptrs+  where+    initStatic (SptEntry sp_id (Fingerprint w1 w2)) = do+      i <- varForId sp_id+      fpa <- concat <$> mapM (genLit . mkLitWord64 . fromIntegral) [w1,w2]+      let sptInsert = ApplExpr (var "h$hs_spt_insert") (fpa ++ [i])+      return $ (var "h$initStatic" .^ "push") `ApplStat` [jLam sptInsert]+
+ compiler/GHC/StgToJS/StgUtils.hs view
@@ -0,0 +1,266 @@+{-# LANGUAGE LambdaCase #-}++module GHC.StgToJS.StgUtils+  ( bindingRefs+  , hasExport+  , collectTopIds+  , collectIds+  , removeTick+  , isUpdatableRhs+  , isInlineExpr+  , exprRefs+  -- * Live vars+  , LiveVars+  , liveVars+  , liveStatic+  , stgRhsLive+  , stgExprLive+  , stgTopBindLive+  , stgLetNoEscapeLive+  , stgLneLiveExpr+  , stgLneLive+  , stgLneLive'+  )+where++import GHC.Prelude++import GHC.Stg.Syntax+import GHC.Core.DataCon+import GHC.Core.Type+import GHC.Core.TyCon++import GHC.Types.Unique.FM+import GHC.Types.Unique.Set+import GHC.Types.Unique+import GHC.Types.Id+import GHC.Types.Id.Info+import GHC.Types.ForeignCall+import GHC.Types.TyThing+import GHC.Types.Name+import GHC.Types.Var.Set++import GHC.Builtin.Names+import GHC.Builtin.PrimOps (PrimOp(SeqOp), primOpIsReallyInline)+import GHC.Utils.Misc (seqList)+import GHC.Utils.Panic++import qualified Data.Foldable as F+import qualified Data.Set      as S+import qualified Data.List     as L+import Data.Set (Set)+import Data.Monoid++s :: a -> Set a+s = S.singleton++l :: (a -> Set Id) -> [a] -> Set Id+l = F.foldMap++-- | collect Ids that this binding refers to+--   (does not include the bindees themselves)+-- first argument is Id -> StgExpr map for unfloated arguments+bindingRefs :: UniqFM Id CgStgExpr -> CgStgBinding -> Set Id+bindingRefs u = \case+  StgNonRec _ rhs -> rhsRefs u rhs+  StgRec bs       -> l (rhsRefs u . snd) bs++rhsRefs :: UniqFM Id CgStgExpr -> CgStgRhs -> Set Id+rhsRefs u = \case+  StgRhsClosure _ _ _ _ body       -> exprRefs u body+  StgRhsCon _ccs d _mu _ticks args -> l s [ i | AnId i <- dataConImplicitTyThings d] <> l (argRefs u) args++exprRefs :: UniqFM Id CgStgExpr -> CgStgExpr -> Set Id+exprRefs u = \case+  StgApp f args             -> s f <> l (argRefs u) args+  StgConApp d _n args _     -> l s [ i | AnId i <- dataConImplicitTyThings d] <> l (argRefs u) args+  StgOpApp _ args _         -> l (argRefs u) args+  StgLit {}                 -> mempty+  StgCase expr _ _ alts     -> exprRefs u expr <> mconcat (fmap (altRefs u) alts)+  StgLet _ bnd expr         -> bindingRefs u bnd <> exprRefs u expr+  StgLetNoEscape _ bnd expr -> bindingRefs u bnd <> exprRefs u expr+  StgTick _ expr            -> exprRefs u expr++altRefs :: UniqFM Id CgStgExpr -> CgStgAlt -> Set Id+altRefs u alt = exprRefs u (alt_rhs alt)++argRefs :: UniqFM Id CgStgExpr -> StgArg -> Set Id+argRefs u = \case+  StgVarArg id+    | Just e <- lookupUFM u id -> exprRefs u e+    | otherwise                -> s id+  _ -> mempty++hasExport :: CgStgBinding -> Bool+hasExport bnd =+  case bnd of+    StgNonRec b e -> isExportedBind b e+    StgRec bs     -> any (uncurry isExportedBind) bs+  where+    isExportedBind _i (StgRhsCon _cc con _ _ _) =+      getUnique con == staticPtrDataConKey+    isExportedBind _ _ = False++collectTopIds :: CgStgBinding -> [Id]+collectTopIds (StgNonRec b _) = [b]+collectTopIds (StgRec bs) = let xs = map (zapFragileIdInfo . fst) bs+                            in  seqList xs `seq` xs++collectIds :: UniqFM Id CgStgExpr -> CgStgBinding -> [Id]+collectIds unfloated b =+  let xs = map zapFragileIdInfo .+           filter acceptId $ S.toList (bindingRefs unfloated b)+  in  seqList xs `seq` xs+  where+    acceptId i = all ($ i) [not . isForbidden] -- fixme test this: [isExported[isGlobalId, not.isForbidden]+    -- the GHC.Prim module has no js source file+    isForbidden i+      | Just m <- nameModule_maybe (getName i) = m == gHC_PRIM+      | otherwise = False++removeTick :: CgStgExpr -> CgStgExpr+removeTick (StgTick _ e) = e+removeTick e             = e++-----------------------------------------------------+-- Live vars+--+-- TODO: should probably be moved into GHC.Stg.LiveVars++type LiveVars = DVarSet++liveStatic :: LiveVars -> LiveVars+liveStatic = filterDVarSet isGlobalId++liveVars :: LiveVars -> LiveVars+liveVars = filterDVarSet (not . isGlobalId)++stgTopBindLive :: CgStgTopBinding -> [(Id, LiveVars)]+stgTopBindLive = \case+  StgTopLifted b     -> stgBindLive b+  StgTopStringLit {} -> []++stgBindLive :: CgStgBinding -> [(Id, LiveVars)]+stgBindLive = \case+  StgNonRec b rhs -> [(b, stgRhsLive rhs)]+  StgRec bs       -> map (\(b,rhs) -> (b, stgRhsLive rhs)) bs++stgBindRhsLive :: CgStgBinding -> LiveVars+stgBindRhsLive b =+  let (bs, ls) = unzip (stgBindLive b)+  in  delDVarSetList (unionDVarSets ls) bs++stgRhsLive :: CgStgRhs -> LiveVars+stgRhsLive = \case+  StgRhsClosure _ _ _ args e -> delDVarSetList (stgExprLive True e) args+  StgRhsCon _ _ _ _ args     -> unionDVarSets (map stgArgLive args)++stgArgLive :: StgArg -> LiveVars+stgArgLive = \case+  StgVarArg occ -> unitDVarSet occ+  StgLitArg {}  -> emptyDVarSet++stgExprLive :: Bool -> CgStgExpr -> LiveVars+stgExprLive includeLHS = \case+  StgApp occ args -> unionDVarSets (unitDVarSet occ : map stgArgLive args)+  StgLit {}       -> emptyDVarSet+  StgConApp _dc _n args _tys -> unionDVarSets (map stgArgLive args)+  StgOpApp _op args _ty      -> unionDVarSets (map stgArgLive args)+  StgCase e b _at alts+    | includeLHS -> el `unionDVarSet` delDVarSet al b+    | otherwise  -> delDVarSet al b+    where+      al = unionDVarSets (map stgAltLive alts)+      el = stgExprLive True e+  StgLet _ b e         -> delDVarSetList (stgBindRhsLive b `unionDVarSet` stgExprLive True e) (bindees b)+  StgLetNoEscape _ b e -> delDVarSetList (stgBindRhsLive b `unionDVarSet` stgExprLive True e) (bindees b)+  StgTick _ti e        -> stgExprLive True e++stgAltLive :: CgStgAlt -> LiveVars+stgAltLive alt =+  delDVarSetList (stgExprLive True (alt_rhs alt)) (alt_bndrs alt)++stgLetNoEscapeLive :: Bool -> StgBinding -> StgExpr -> LiveVars+stgLetNoEscapeLive _someBool _b _e = panic "stgLetNoEscapeLive"++bindees :: CgStgBinding -> [Id]+bindees = \case+  StgNonRec b _e -> [b]+  StgRec bs      -> map fst bs++isUpdatableRhs :: CgStgRhs -> Bool+isUpdatableRhs (StgRhsClosure _ _ u _ _) = isUpdatable u+isUpdatableRhs _                         = False++stgLneLive' :: CgStgBinding -> [Id]+stgLneLive' b = filter (`notElem` bindees b) (stgLneLive b)++stgLneLive :: CgStgBinding -> [Id]+stgLneLive (StgNonRec _b e) = stgLneLiveExpr e+stgLneLive (StgRec bs)      = L.nub $ concatMap (stgLneLiveExpr . snd) bs++stgLneLiveExpr :: CgStgRhs -> [Id]+stgLneLiveExpr rhs = dVarSetElems (liveVars $ stgRhsLive rhs)+-- stgLneLiveExpr (StgRhsClosure _ _ _ _ e) = dVarSetElems (liveVars (stgExprLive e))+-- stgLneLiveExpr StgRhsCon {}              = []++-- | returns True if the expression is definitely inline+isInlineExpr :: UniqSet Id -> CgStgExpr -> (UniqSet Id, Bool)+isInlineExpr v = \case+  StgApp i args+    -> (emptyUniqSet, isInlineApp v i args)+  StgLit{}+    -> (emptyUniqSet, True)+  StgConApp{}+    -> (emptyUniqSet, True)+  StgOpApp (StgFCallOp f _) _ _+    -> (emptyUniqSet, isInlineForeignCall f)+  StgOpApp (StgPrimOp SeqOp) [StgVarArg e] t+    -> (emptyUniqSet, e `elementOfUniqSet` v || isStrictType t)+  StgOpApp (StgPrimOp op) _ _+    -> (emptyUniqSet, primOpIsReallyInline op)+  StgOpApp (StgPrimCallOp _c) _ _+    -> (emptyUniqSet, True)+  StgCase e b _ alts+    ->let (_ve, ie)   = isInlineExpr v e+          v'          = addOneToUniqSet v b+          (vas, ias)  = unzip $ map (isInlineExpr v') (fmap alt_rhs alts)+          vr          = L.foldl1' intersectUniqSets vas+      in (vr, (ie || b `elementOfUniqSet` v) && and ias)+  StgLet _ b e+    -> isInlineExpr (inspectInlineBinding v b) e+  StgLetNoEscape _ _b e+    -> isInlineExpr v e+  StgTick  _ e+    -> isInlineExpr v e++inspectInlineBinding :: UniqSet Id -> CgStgBinding -> UniqSet Id+inspectInlineBinding v = \case+  StgNonRec i r -> inspectInlineRhs v i r+  StgRec bs     -> foldl' (\v' (i,r) -> inspectInlineRhs v' i r) v bs++inspectInlineRhs :: UniqSet Id -> Id -> CgStgRhs -> UniqSet Id+inspectInlineRhs v i = \case+  StgRhsCon{}                     -> addOneToUniqSet v i+  StgRhsClosure _ _ ReEntrant _ _ -> addOneToUniqSet v i+  _                               -> v++isInlineForeignCall :: ForeignCall -> Bool+isInlineForeignCall (CCall (CCallSpec _ cconv safety)) =+  not (playInterruptible safety) &&+  not (cconv /= JavaScriptCallConv && playSafe safety)++isInlineApp :: UniqSet Id -> Id -> [StgArg] -> Bool+isInlineApp v i = \case+  _ | isJoinId i -> False+  [] -> isUnboxedTupleType (idType i) ||+                     isStrictType (idType i) ||+                     i `elementOfUniqSet` v++  [StgVarArg a]+    | DataConWrapId dc <- idDetails i+    , isNewTyCon (dataConTyCon dc)+    , isStrictType (idType a) || a `elementOfUniqSet` v || isStrictId a+    -> True+  _ -> False+
+ compiler/GHC/StgToJS/Symbols.hs view
@@ -0,0 +1,89 @@++-- | JS symbol generation+module GHC.StgToJS.Symbols+  ( moduleGlobalSymbol+  , moduleExportsSymbol+  , mkJsSymbol+  , mkJsSymbolBS+  , mkFreshJsSymbol+  , mkRawSymbol+  , intBS+  ) where++import GHC.Prelude++import GHC.Data.FastString+import GHC.Unit.Module+import Data.ByteString (ByteString)+import qualified Data.ByteString.Char8   as BSC+import qualified Data.ByteString.Builder as BSB+import qualified Data.ByteString.Lazy    as BSL++-- | Hexadecimal representation of an int+--+-- Used for uniques. We could use base-62 as GHC usually does but this is likely+-- faster.+intBS :: Int -> ByteString+intBS = BSL.toStrict . BSB.toLazyByteString . BSB.wordHex . fromIntegral++-- | Return z-encoded unit:module+unitModuleStringZ :: Module -> ByteString+unitModuleStringZ mod = mconcat+  [ fastZStringToByteString (zEncodeFS (unitIdFS (moduleUnitId mod)))+  , BSC.pack "ZC" -- z-encoding for ":"+  , fastZStringToByteString (zEncodeFS (moduleNameFS (moduleName mod)))+  ]++-- | the global linkable unit of a module exports this symbol, depend on it to+--   include that unit (used for cost centres)+moduleGlobalSymbol :: Module -> FastString+moduleGlobalSymbol m = mkFastStringByteString $ mconcat+  [ hd+  , unitModuleStringZ m+  , BSC.pack "_<global>"+  ]++moduleExportsSymbol :: Module -> FastString+moduleExportsSymbol m = mkFastStringByteString $ mconcat+  [ hd+  , unitModuleStringZ m+  , BSC.pack "_<exports>"+  ]++-- | Make JS symbol corresponding to the given Haskell symbol in the given+-- module+mkJsSymbolBS :: Bool -> Module -> FastString -> ByteString+mkJsSymbolBS exported mod s = mconcat+  [ if exported then hd else hdd+  , unitModuleStringZ mod+  , BSC.pack "zi" -- z-encoding of "."+  , fastZStringToByteString (zEncodeFS s)+  ]++-- | Make JS symbol corresponding to the given Haskell symbol in the given+-- module+mkJsSymbol :: Bool -> Module -> FastString -> FastString+mkJsSymbol exported mod s = mkFastStringByteString (mkJsSymbolBS exported mod s)++-- | Make JS symbol for given module and unique.+mkFreshJsSymbol :: Module -> Int -> FastString+mkFreshJsSymbol mod i = mkFastStringByteString $ mconcat+  [ hdd+  , unitModuleStringZ mod+  , BSC.pack "_"+  , intBS i+  ]++-- | Make symbol "h$XYZ" or "h$$XYZ"+mkRawSymbol :: Bool -> FastString -> FastString+mkRawSymbol exported fs+  | exported  = mkFastStringByteString $ mconcat [ hd,  bytesFS fs ]+  | otherwise = mkFastStringByteString $ mconcat [ hdd, bytesFS fs ]++-- | "h$$" constant string+hdd :: ByteString+hdd = BSC.pack "h$$"++-- | "h$" constant string+hd :: ByteString+hd = BSC.take 2 hdd
+ compiler/GHC/StgToJS/Types.hs view
@@ -0,0 +1,430 @@+{-# LANGUAGE DeriveGeneric              #-}+{-# LANGUAGE DerivingStrategies         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase                 #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  GHC.StgToJS.Types+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file LICENSE)+--+-- Maintainer  :  Jeffrey Young  <jeffrey.young@iohk.io>+--                Luite Stegeman <luite.stegeman@iohk.io>+--                Sylvain Henry  <sylvain.henry@iohk.io>+--                Josh Meredith  <josh.meredith@iohk.io>+-- Stability   :  experimental+--+--+-- Module that holds the Types required for the StgToJS pass+-----------------------------------------------------------------------------++module GHC.StgToJS.Types where++import GHC.Prelude++import GHC.JS.Syntax+import GHC.JS.Make+import GHC.JS.Ppr ()++import GHC.Stg.Syntax+import GHC.Core.TyCon++import GHC.Types.Unique+import GHC.Types.Unique.FM+import GHC.Types.Var+import GHC.Types.ForeignCall++import Control.Monad.Trans.State.Strict+import GHC.Utils.Outputable (Outputable (..), text, SDocContext, (<+>), ($$))++import GHC.Data.FastString+import GHC.Data.FastMutInt++import GHC.Unit.Module++import qualified Data.Map as M+import           Data.Set (Set)+import qualified Data.ByteString as BS+import           Data.Monoid+import           Data.Typeable (Typeable)+import           GHC.Generics (Generic)+import           Control.DeepSeq++-- | A State monad over IO holding the generator state.+type G = StateT GenState IO++-- | The JS code generator state+data GenState = GenState+  { gsSettings  :: !StgToJSConfig         -- ^ codegen settings, read-only+  , gsModule    :: !Module                -- ^ current module+  , gsId        :: {-# UNPACK #-} !FastMutInt -- ^ unique number for the id generator+  , gsIdents    :: !IdCache               -- ^ hash consing for identifiers from a Unique+  , gsUnfloated :: !(UniqFM Id CgStgExpr) -- ^ unfloated arguments+  , gsGroup     :: GenGroupState          -- ^ state for the current binding group+  , gsGlobal    :: [JStat]                -- ^ global (per module) statements (gets included when anything else from the module is used)+  }++-- | The JS code generator state relevant for the current binding group+data GenGroupState = GenGroupState+  { ggsToplevelStats :: [JStat]        -- ^ extra toplevel statements for the binding group+  , ggsClosureInfo   :: [ClosureInfo]  -- ^ closure metadata (info tables) for the binding group+  , ggsStatic        :: [StaticInfo]   -- ^ static (CAF) data in our binding group+  , ggsStack         :: [StackSlot]    -- ^ stack info for the current expression+  , ggsStackDepth    :: Int            -- ^ current stack depth+  , ggsExtraDeps     :: Set OtherSymb  -- ^ extra dependencies for the linkable unit that contains this group+  , ggsGlobalIdCache :: GlobalIdCache+  , ggsForeignRefs   :: [ForeignJSRef]+  }++-- | The Configuration record for the StgToJS pass+data StgToJSConfig = StgToJSConfig+  -- flags+  { csInlinePush      :: !Bool+  , csInlineBlackhole :: !Bool+  , csInlineLoadRegs  :: !Bool+  , csInlineEnter     :: !Bool+  , csInlineAlloc     :: !Bool+  , csTraceRts        :: !Bool+  , csAssertRts       :: !Bool+  , csBoundsCheck     :: !Bool+  , csDebugAlloc      :: !Bool+  , csTraceForeign    :: !Bool+  , csProf            :: !Bool -- ^ Profiling enabled+  , csRuntimeAssert   :: !Bool -- ^ Enable runtime assertions+  -- settings+  , csContext         :: !SDocContext+  }++-- | Information relevenat to code generation for closures.+data ClosureInfo = ClosureInfo+  { ciVar     :: Ident      -- ^ object being infod+  , ciRegs    :: CIRegs     -- ^ size of the payload (in number of JS values)+  , ciName    :: FastString -- ^ friendly name for printing+  , ciLayout  :: CILayout   -- ^ heap/stack layout of the object+  , ciType    :: CIType     -- ^ type of the object, with extra info where required+  , ciStatic  :: CIStatic   -- ^ static references of this object+  }+  deriving stock (Eq, Show, Generic)++-- | Closure information, 'ClosureInfo', registers+data CIRegs+  = CIRegsUnknown                     -- ^ A value witnessing a state of unknown registers+  | CIRegs { ciRegsSkip  :: Int       -- ^ unused registers before actual args start+           , ciRegsTypes :: [VarType] -- ^ args+           }+  deriving stock (Eq, Ord, Show, Generic)++instance NFData CIRegs++-- | Closure Information, 'ClosureInfo', layout+data CILayout+  = CILayoutVariable            -- ^ layout stored in object itself, first position from the start+  | CILayoutUnknown             -- ^ fixed size, but content unknown (for example stack apply frame)+      { layoutSize :: !Int+      }+  | CILayoutFixed               -- ^ whole layout known+      { layoutSize :: !Int      -- ^ closure size in array positions, including entry+      , layout     :: [VarType] -- ^ The set of sized Types to layout+      }+  deriving stock (Eq, Ord, Show, Generic)++instance NFData CILayout++-- | The type of 'ClosureInfo'+data CIType+  = CIFun { citArity :: !Int         -- ^ function arity+          , citRegs  :: !Int         -- ^ number of registers for the args+          }+  | CIThunk                          -- ^ The closure is a THUNK+  | CICon { citConstructor :: !Int } -- ^ The closure is a Constructor+  | CIPap                            -- ^ The closure is a Partial Application+  | CIBlackhole                      -- ^ The closure is a black hole+  | CIStackFrame                     -- ^ The closure is a stack frame+  deriving stock (Eq, Ord, Show, Generic)++instance NFData CIType++-- | Static references that must be kept alive+newtype CIStatic = CIStaticRefs { staticRefs :: [FastString] }+  deriving stock   (Eq, Generic)+  deriving newtype (Semigroup, Monoid, Show)++-- | static refs: array = references, null = nothing to report+--   note: only works after all top-level objects have been created+instance ToJExpr CIStatic where+  toJExpr (CIStaticRefs [])  = null_ -- [je| null |]+  toJExpr (CIStaticRefs rs)  = toJExpr (map TxtI rs)++-- | Free variable types+data VarType+  = PtrV     -- ^ pointer = reference to heap object (closure object)+  | VoidV    -- ^ no fields+  | DoubleV  -- ^ A Double: one field+  | IntV     -- ^ An Int (32bit because JS): one field+  | LongV    -- ^ A Long: two fields one for the upper 32bits, one for the lower (NB: JS is little endian)+  | AddrV    -- ^ a pointer not to the heap: two fields, array + index+  | RtsObjV  -- ^ some RTS object from GHCJS (for example TVar#, MVar#, MutVar#, Weak#)+  | ObjV     -- ^ some JS object, user supplied, be careful around these, can be anything+  | ArrV     -- ^ boxed array+  deriving stock (Eq, Ord, Enum, Bounded, Show, Generic)++instance NFData VarType++instance ToJExpr VarType where+  toJExpr = toJExpr . fromEnum++-- | The type of identifiers. These determine the suffix of generated functions+-- in JS Land. For example, the entry function for the 'Just' constructor is a+-- 'IdConEntry' which compiles to:+-- @+-- function h$baseZCGHCziMaybeziJust_con_e() { return h$rs() };+-- @+-- which just returns whatever the stack point is pointing to. Whereas the entry+-- function to 'Just' is an 'IdEntry' and does the work. It compiles to:+-- @+-- function h$baseZCGHCziMaybeziJust_e() {+--    var h$$baseZCGHCziMaybezieta_8KXnScrCjF5 = h$r2;+--    h$r1 = h$c1(h$baseZCGHCziMaybeziJust_con_e, h$$baseZCGHCziMaybezieta_8KXnScrCjF5);+--    return h$rs();+--    };+-- @+-- Which loads some payload from register 2, and applies the Constructor Entry+-- function for the Just to the payload, returns the result in register 1 and+-- returns whatever is on top of the stack+data IdType+  = IdPlain     -- ^ A plain identifier for values, no suffix added+  | IdEntry     -- ^ An entry function, suffix = "_e" in 'GHC.StgToJS.Ids.makeIdentForId'+  | IdConEntry  -- ^ A Constructor entry function, suffix = "_con_e" in 'GHC.StgToJS.Ids.makeIdentForId'+  deriving (Enum, Eq, Ord)++-- | Keys to differentiate Ident's in the ID Cache+data IdKey+  = IdKey !Int !Int !IdType+  deriving (Eq, Ord)++-- | Some other symbol+data OtherSymb+  = OtherSymb !Module !FastString+  deriving Eq++instance Ord OtherSymb where+  compare (OtherSymb m1 t1) (OtherSymb m2 t2)+    = stableModuleCmp m1 m2 <> lexicalCompareFS t1 t2++-- | The identifier cache indexed on 'IdKey' local to a module+newtype IdCache = IdCache (M.Map IdKey Ident)++-- | The global Identifier Cache+newtype GlobalIdCache = GlobalIdCache (UniqFM Ident (IdKey, Id))++-- | A Stack Slot is either known or unknown. We avoid maybe here for more+-- strictness.+data StackSlot+  = SlotId !Id !Int+  | SlotUnknown+  deriving (Eq, Ord)++data StaticInfo = StaticInfo+  { siVar    :: !FastString    -- ^ global object+  , siVal    :: !StaticVal     -- ^ static initialization+  , siCC     :: !(Maybe Ident) -- ^ optional CCS name+  } deriving stock (Eq, Show, Typeable, Generic)++data StaticVal+  = StaticFun     !FastString [StaticArg]+    -- ^ heap object for function+  | StaticThunk   !(Maybe (FastString,[StaticArg]))+    -- ^ heap object for CAF (field is Nothing when thunk is initialized in an+    -- alternative way, like string thunks through h$str)+  | StaticUnboxed !StaticUnboxed+    -- ^ unboxed constructor (Bool, Int, Double etc)+  | StaticData    !FastString [StaticArg]+    -- ^ regular datacon app+  | StaticList    [StaticArg] (Maybe FastString)+    -- ^ list initializer (with optional tail)+  deriving stock (Eq, Show, Generic)++data StaticUnboxed+  = StaticUnboxedBool         !Bool+  | StaticUnboxedInt          !Integer+  | StaticUnboxedDouble       !SaneDouble+  | StaticUnboxedString       !BS.ByteString+  | StaticUnboxedStringOffset !BS.ByteString+  deriving stock (Eq, Ord, Show, Generic)++instance NFData StaticUnboxed++-- | Static Arguments. Static Arguments are things that are statically+-- allocated, i.e., they exist at program startup. These are static heap objects+-- or literals or things that have been floated to the top level binding by ghc.+data StaticArg+  = StaticObjArg !FastString             -- ^ reference to a heap object+  | StaticLitArg !StaticLit              -- ^ literal+  | StaticConArg !FastString [StaticArg] -- ^ unfloated constructor+  deriving stock (Eq, Show, Generic)++instance Outputable StaticArg where+  ppr x = text (show x)++-- | A Static literal value+data StaticLit+  = BoolLit   !Bool+  | IntLit    !Integer+  | NullLit+  | DoubleLit !SaneDouble -- should we actually use double here?+  | StringLit !FastString+  | BinLit    !BS.ByteString+  | LabelLit  !Bool !FastString -- ^ is function pointer, label (also used for string / binary init)+  deriving (Eq, Show, Generic)++instance Outputable StaticLit where+  ppr x = text (show x)+++instance ToJExpr StaticLit where+  toJExpr (BoolLit b)           = toJExpr b+  toJExpr (IntLit i)            = toJExpr i+  toJExpr NullLit               = null_+  toJExpr (DoubleLit d)         = toJExpr (unSaneDouble d)+  toJExpr (StringLit t)         = app (mkFastString "h$str") [toJExpr t]+  toJExpr (BinLit b)            = app (mkFastString "h$rstr") [toJExpr (map toInteger (BS.unpack b))]+  toJExpr (LabelLit _isFun lbl) = var lbl++-- | A foreign reference to some JS code+data ForeignJSRef = ForeignJSRef+  { foreignRefSrcSpan  :: !FastString+  , foreignRefPattern  :: !FastString+  , foreignRefSafety   :: !Safety+  , foreignRefCConv    :: !CCallConv+  , foreignRefArgs     :: ![FastString]+  , foreignRefResult   :: !FastString+  } deriving stock (Generic)++-- | data used to generate one ObjUnit in our object file+data LinkableUnit = LinkableUnit+  { luObjUnit      :: ObjUnit       -- ^ serializable unit info+  , luIdExports    :: [Id]          -- ^ exported names from haskell identifiers+  , luOtherExports :: [FastString]  -- ^ other exports+  , luIdDeps       :: [Id]          -- ^ identifiers this unit depends on+  , luPseudoIdDeps :: [Unique]      -- ^ pseudo-id identifiers this unit depends on (fixme)+  , luOtherDeps    :: [OtherSymb]   -- ^ symbols not from a haskell id that this unit depends on+  , luRequired     :: Bool          -- ^ always link this unit+  , luForeignRefs  :: [ForeignJSRef]+  }++-- | one toplevel block in the object file+data ObjUnit = ObjUnit+  { oiSymbols  :: ![FastString]   -- ^ toplevel symbols (stored in index)+  , oiClInfo   :: ![ClosureInfo]  -- ^ closure information of all closures in block+  , oiStatic   :: ![StaticInfo]   -- ^ static closure data+  , oiStat     :: JStat           -- ^ the code+  , oiRaw      :: !BS.ByteString  -- ^ raw JS code+  , oiFExports :: ![ExpFun]+  , oiFImports :: ![ForeignJSRef]+  }++data ExpFun = ExpFun+  { isIO   :: !Bool+  , args   :: [JSFFIType]+  , result :: !JSFFIType+  } deriving (Eq, Ord, Show)++-- | Types of FFI values+data JSFFIType+  = Int8Type+  | Int16Type+  | Int32Type+  | Int64Type+  | Word8Type+  | Word16Type+  | Word32Type+  | Word64Type+  | DoubleType+  | ByteArrayType+  | PtrType+  | RefType+  deriving (Show, Ord, Eq, Enum)+++-- | Typed expression+data TypedExpr = TypedExpr+  { typex_typ  :: !PrimRep+  , typex_expr :: [JExpr]+  }++instance Outputable TypedExpr where+  ppr x = text "TypedExpr: " <+> ppr (typex_expr x)+          $$  text "PrimReps: " <+> ppr (typex_typ x)++-- | A Primop result is either an inlining of some JS payload, or a primitive+-- call to a JS function defined in Shim files in base.+data PrimRes+  = PrimInline JStat  -- ^ primop is inline, result is assigned directly+  | PRPrimCall JStat  -- ^ primop is async call, primop returns the next+                      --     function to run. result returned to stack top in registers++data ExprResult+  = ExprCont+  | ExprInline (Maybe [JExpr])+  deriving (Eq)++newtype ExprValData = ExprValData [JExpr]+  deriving newtype (Eq)++-- | A Closure is one of six types+data ClosureType+  = Thunk       -- ^ The closure is a THUNK+  | Fun         -- ^ The closure is a Function+  | Pap         -- ^ The closure is a Partial Application+  | Con         -- ^ The closure is a Constructor+  | Blackhole   -- ^ The closure is a Blackhole+  | StackFrame  -- ^ The closure is a stack frame+  deriving (Show, Eq, Ord, Enum, Bounded)++-- | Convert 'ClosureType' to an Int+ctNum :: ClosureType -> Int+ctNum Fun        = 1+ctNum Con        = 2+ctNum Thunk      = 0+ctNum Pap        = 3+ctNum Blackhole  = 5+ctNum StackFrame = -1++-- | Convert 'ClosureType' to a String+ctJsName :: ClosureType -> String+ctJsName = \case+  Thunk      -> "CLOSURE_TYPE_THUNK"+  Fun        -> "CLOSURE_TYPE_FUN"+  Pap        -> "CLOSURE_TYPE_PAP"+  Con        -> "CLOSURE_TYPE_CON"+  Blackhole  -> "CLOSURE_TYPE_BLACKHOLE"+  StackFrame -> "CLOSURE_TYPE_STACKFRAME"++instance ToJExpr ClosureType where+  toJExpr e = toJExpr (ctNum e)+++-- | A thread is in one of 4 states+data ThreadStatus+  = Running   -- ^ The thread is running+  | Blocked   -- ^ The thread is blocked+  | Finished  -- ^ The thread is done+  | Died      -- ^ The thread has died+  deriving (Show, Eq, Ord, Enum, Bounded)++-- | Convert the status of a thread in JS land to an Int+threadStatusNum :: ThreadStatus -> Int+threadStatusNum = \case+  Running  -> 0+  Blocked  -> 1+  Finished -> 16+  Died     -> 17++-- | convert the status of a thread in JS land to a string+threadStatusJsName :: ThreadStatus -> String+threadStatusJsName = \case+  Running  -> "THREAD_RUNNING"+  Blocked  -> "THREAD_BLOCKED"+  Finished -> "THREAD_FINISHED"+  Died     -> "THREAD_DIED"
+ compiler/GHC/StgToJS/Utils.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE OverloadedStrings #-}++module GHC.StgToJS.Utils+  ( assignToTypedExprs+  , assignCoerce1+  , assignToExprCtx+  )+where++import GHC.Prelude++import GHC.StgToJS.Types+import GHC.StgToJS.ExprCtx++import GHC.JS.Syntax+import GHC.JS.Make++import GHC.Core.TyCon++import GHC.Utils.Misc+import GHC.Utils.Panic+import GHC.Utils.Outputable++assignToTypedExprs :: HasDebugCallStack => [TypedExpr] -> [JExpr] -> JStat+assignToTypedExprs tes es =+  assignAllEqual (concatMap typex_expr tes) es++assignTypedExprs :: [TypedExpr] -> [TypedExpr] -> JStat+assignTypedExprs tes es =+  -- TODO: check primRep (typex_typ) here?+  assignToTypedExprs tes (concatMap typex_expr es)++assignToExprCtx :: HasDebugCallStack => ExprCtx -> [JExpr] -> JStat+assignToExprCtx ctx es = assignToTypedExprs (ctxTarget ctx) es++-- | Assign first expr only (if it exists), performing coercions between some+-- PrimReps (e.g. StablePtr# and Addr#).+assignCoerce1 :: HasDebugCallStack => [TypedExpr] -> [TypedExpr] -> JStat+assignCoerce1 [x] [y] = assignCoerce x y+assignCoerce1 []  []  = mempty+assignCoerce1 x   y   = pprPanic "assignCoerce1"+                          (vcat [ text "lengths do not match"+                                , ppr x+                                , ppr y+                                ])++-- | Assign p2 to p1 with optional coercion+assignCoerce :: TypedExpr -> TypedExpr -> JStat+-- Coercion between StablePtr# and Addr#+assignCoerce (TypedExpr AddrRep [a_val, a_off]) (TypedExpr UnliftedRep [sptr]) = mconcat+    [ a_val |= var "h$stablePtrBuf"+    , a_off |= sptr+    ]+assignCoerce (TypedExpr UnliftedRep [sptr]) (TypedExpr AddrRep [_a_val, a_off]) =+  sptr |= a_off+assignCoerce p1 p2 = assignTypedExprs [p1] [p2]+
compiler/GHC/SysTools/Cpp.hs view
@@ -231,4 +231,3 @@ offsetIncludePaths dflags (IncludeSpecs incs quotes impl) =      let go = map (augmentByWorkingDirectory dflags)      in IncludeSpecs (go incs) (go quotes) (go impl)-
compiler/GHC/SysTools/Info.hs view
@@ -113,7 +113,7 @@          | any (\line -> "LLD" `isPrefixOf` line || "LLD" `elem` words line) stdo =           return (LlvmLLD $ map Option [ --see Note [ELF needed shared libs]-                                        "-Wl,--no-as-needed"])+                                        "-Wl,--no-as-needed" | osElfTarget os || os == OSMinGW32 ])           -- Unknown linker.         | otherwise = fail "invalid --version output, or linker is unsupported"
compiler/GHC/SysTools/Tasks.hs view
@@ -159,6 +159,10 @@                         ,pgm_c dflags,    "Asm Compiler")           RawObject  -> ("c",             []                         ,pgm_c dflags,    "C Compiler") -- claim C for lack of a better idea+          --JS backend shouldn't reach here, so we just pass+          -- strings to satisfy the totality checker+          LangJs     -> ("js",            []+                        ,pgm_c dflags,    "JS Backend Compiler")   userOpts_c   = getOpts dflags opt_c   userOpts_cxx = getOpts dflags opt_cxx @@ -220,6 +224,12 @@             text "(or GHC tried to execute clang incorrectly)"         throwIO err     )++runEmscripten :: Logger -> DynFlags -> [Option] -> IO ()+runEmscripten logger dflags args = traceSystoolCommand logger "emcc" $ do+  let (p,args0) = pgm_a dflags+      args1     = args0 ++ args+  runSomething logger "Emscripten" p args1  -- | Figure out which version of LLVM we are running this session figureLlvmVersion :: Logger -> DynFlags -> IO (Maybe LlvmVersion)
compiler/GHC/Tc/Deriv.hs view
@@ -635,8 +635,8 @@                   -- is the case.                |  Just inst_ty <- lastMaybe inst_tys                -> do-               let via_kind     = tcTypeKind via_ty-                   inst_ty_kind = tcTypeKind inst_ty+               let via_kind     = typeKind via_ty+                   inst_ty_kind = typeKind inst_ty                    mb_match     = tcUnifyTy inst_ty_kind via_kind                 checkTc (isJust mb_match)@@ -747,7 +747,7 @@                                 -- See Note [tc_args and tycon arity]               (tc_args_to_keep, args_to_drop)                               = splitAt n_args_to_keep tc_args-              inst_ty_kind    = tcTypeKind (mkTyConApp tc tc_args_to_keep)+              inst_ty_kind    = typeKind (mkTyConApp tc tc_args_to_keep)                -- Match up the kinds, and apply the resulting kind substitution               -- to the types.  See Note [Unify kinds in deriving]@@ -756,6 +756,12 @@               enough_args     = n_args_to_keep >= 0          -- Check that the result really is well-kinded+        ; traceTc "deriveTyData" $+          vcat [ text "class:" <+> ppr cls <+> dcolon <+> ppr (tyConKind (classTyCon cls))+               , text "cls_tys:" <+> ppr cls_tys+               , text "tycon:" <+> ppr tc <+> dcolon <+> ppr (tyConKind tc)+               , text "cls_arg:" <+> ppr (mkTyConApp tc tc_args_to_keep) <+> dcolon <+> ppr inst_ty_kind+               , text "cls_arg_kind:" <+> ppr cls_arg_kind ]         ; checkTc (enough_args && isJust mb_match)                   (TcRnCannotDeriveInstance cls cls_tys Nothing NoGeneralizedNewtypeDeriving $                      DerivErrNotWellKinded tc cls_arg_kind n_args_to_keep)@@ -797,9 +803,9 @@               -- Perform an additional unification with the kind of the `via`               -- type and the result of the previous kind unification.               Just (ViaStrategy via_ty) -> do-                let via_kind = tcTypeKind via_ty+                let via_kind = typeKind via_ty                     inst_ty_kind-                              = tcTypeKind (mkTyConApp tc tc_args')+                              = typeKind (mkTyConApp tc tc_args')                     via_match = tcUnifyTy inst_ty_kind via_kind                  checkTc (isJust via_match)
compiler/GHC/Tc/Deriv/Functor.hs view
@@ -505,11 +505,11 @@        -> Type        -> (a, Bool)   -- (result of type a, does type contain var) -    go co ty | Just ty' <- tcView ty = go co ty'+    go co ty | Just ty' <- coreView ty = go co ty'     go co (TyVarTy    v) | v == var = (if co then caseCoVar else caseVar,True)     go co (FunTy { ft_arg = x, ft_res = y, ft_af = af })-       | InvisArg <- af = go co y-       | xc || yc       = (caseFun xr yr,True)+       | isInvisibleFunArg af = go co y+       | xc || yc             = (caseFun xr yr,True)        where (xr,xc) = go (not co) x              (yr,yc) = go co       y     go co (AppTy    x y) | xc = (caseWrongArg,   True)@@ -532,8 +532,8 @@          -- actually needs. See #12399          (xrs,xcs) = unzip (map (go co) (dropRuntimeRepArgs args))     go co (ForAllTy (Bndr v vis) x)-       | isVisibleArgFlag vis = panic "unexpected visible binder"-       | v /= var && xc       = (caseForAll v xr,True)+       | isVisibleForAllTyFlag vis = panic "unexpected visible binder"+       | v /= var && xc            = (caseForAll v xr,True)        where (xr,xc) = go co x      go _ _ = (caseTrivial,False)
compiler/GHC/Tc/Deriv/Generate.hs view
@@ -72,6 +72,7 @@ import GHC.Builtin.Types import GHC.Core.Type import GHC.Core.Class+ import GHC.Types.Unique.FM ( lookupUFM, listToUFM ) import GHC.Types.Var.Env import GHC.Utils.Misc
compiler/GHC/Tc/Deriv/Generics.hs view
@@ -24,18 +24,22 @@ import GHC.Prelude hiding (head, init, last, tail)  import GHC.Hs-import GHC.Core.Type import GHC.Tc.Utils.TcType import GHC.Tc.Deriv.Generate import GHC.Tc.Deriv.Functor import GHC.Tc.Errors.Types+import GHC.Tc.Instance.Family++import GHC.Core.Type import GHC.Core.DataCon import GHC.Core.TyCon import GHC.Core.FamInstEnv ( FamInst, FamFlavor(..), mkSingleCoAxiom )-import GHC.Tc.Instance.Family+ import GHC.Unit.Module ( moduleName, moduleUnit                        , unitFS, getModule )+ import GHC.Iface.Env    ( newGlobalBinder )+ import GHC.Types.Name hiding ( varName ) import GHC.Types.Name.Reader import GHC.Types.SourceText@@ -343,7 +347,7 @@ gk2gkDC :: GenericKind -> DataCon -> [Type] -> GenericKind_DC gk2gkDC Gen0 _  _       = Gen0_DC gk2gkDC Gen1 dc tc_args = Gen1_DC $ assert (isTyVarTy last_dc_inst_univ)-                                  $ getTyVar "gk2gkDC" last_dc_inst_univ+                                  $ getTyVar last_dc_inst_univ   where     dc_inst_univs = dataConInstUnivs dc tc_args     last_dc_inst_univ = assert (not (null dc_inst_univs)) $
compiler/GHC/Tc/Deriv/Infer.hs view
@@ -16,16 +16,6 @@  import GHC.Prelude -import GHC.Data.Bag-import GHC.Types.Basic-import GHC.Core.Class-import GHC.Core.DataCon-import GHC.Utils.Error-import GHC.Utils.Outputable-import GHC.Utils.Panic-import GHC.Utils.Panic.Plain-import GHC.Data.Pair-import GHC.Builtin.Names import GHC.Tc.Deriv.Utils import GHC.Tc.Utils.Env import GHC.Tc.Deriv.Generate@@ -35,21 +25,36 @@ import GHC.Tc.Utils.Monad import GHC.Tc.Types.Origin import GHC.Tc.Types.Constraint-import GHC.Core.Predicate import GHC.Tc.Utils.TcType-import GHC.Core.TyCon-import GHC.Core.TyCo.Ppr (pprTyVars)-import GHC.Core.Type import GHC.Tc.Solver import GHC.Tc.Solver.Monad ( runTcS ) import GHC.Tc.Validity (validDerivPred) import GHC.Tc.Utils.Unify (buildImplicationFor)-import GHC.Builtin.Types (typeToTypeKind)++import GHC.Core.Class+import GHC.Core.DataCon+import GHC.Core.TyCon+import GHC.Core.TyCo.Ppr (pprTyVars)+import GHC.Core.Type+import GHC.Core.Predicate import GHC.Core.Unify (tcUnifyTy)++import GHC.Data.Pair+import GHC.Builtin.Names+import GHC.Builtin.Types (typeToTypeKind)++import GHC.Utils.Error+import GHC.Utils.Outputable+import GHC.Utils.Panic+import GHC.Utils.Panic.Plain import GHC.Utils.Misc++import GHC.Types.Basic import GHC.Types.Var import GHC.Types.Var.Set +import GHC.Data.Bag+ import Control.Monad import Control.Monad.Trans.Class  (lift) import Control.Monad.Trans.Reader (ask)@@ -236,7 +241,7 @@            is_generic  = main_cls `hasKey` genClassKey            is_generic1 = main_cls `hasKey` gen1ClassKey            -- is_functor_like: see Note [Inferring the instance context]-           is_functor_like = tcTypeKind inst_ty `tcEqKind` typeToTypeKind+           is_functor_like = typeKind inst_ty `tcEqKind` typeToTypeKind                           || is_generic1             get_gen1_constraints ::@@ -288,7 +293,7 @@            -- message which points out the kind mismatch.            -- See Note [Inferring the instance context]            mk_functor_like_constraints orig t_or_k cls-              = map $ \ty -> let ki = tcTypeKind ty in+              = map $ \ty -> let ki = typeKind ty in                              ( [ mk_cls_pred orig t_or_k cls ty                                , SimplePredSpec                                    { sps_pred = mkPrimEqPred ki typeToTypeKind@@ -309,7 +314,7 @@            --         and we need the Data constraints to typecheck the method            extra_constraints                  | main_cls `hasKey` dataClassKey-                 , all (isLiftedTypeKind . tcTypeKind) rep_tc_args+                 , all (isLiftedTypeKind . typeKind) rep_tc_args                  = [ mk_cls_pred deriv_origin t_or_k main_cls ty                    | (t_or_k, ty) <- zip t_or_ks rep_tc_args]                  | otherwise
compiler/GHC/Tc/Deriv/Utils.hs view
@@ -28,23 +28,8 @@  import GHC.Data.Bag import GHC.Types.Basic-import GHC.Core.Class-import GHC.Core.DataCon-import GHC.Core.FamInstEnv-import GHC.Driver.Session-import GHC.Utils.Error-import GHC.Types.Fixity.Env (lookupFixity)-import GHC.Hs+ import GHC.Tc.Utils.Instantiate-import GHC.Core.InstEnv-import GHC.Iface.Load   (loadInterfaceForName)-import GHC.Unit.Module (getModule)-import GHC.Unit.Module.ModIface (mi_fix)-import GHC.Types.Name-import GHC.Utils.Outputable-import GHC.Utils.Panic-import GHC.Builtin.Names-import GHC.Types.SrcLoc import GHC.Tc.Deriv.Generate import GHC.Tc.Deriv.Functor import GHC.Tc.Deriv.Generics@@ -55,11 +40,32 @@ import GHC.Tc.Utils.TcType import GHC.Tc.Utils.Unify (tcSubTypeSigma) import GHC.Tc.Utils.Zonk-import GHC.Builtin.Names.TH (liftClassKey)++import GHC.Core.Class+import GHC.Core.DataCon+import GHC.Core.FamInstEnv+import GHC.Core.InstEnv import GHC.Core.TyCon import GHC.Core.Type++import GHC.Hs+import GHC.Driver.Session+import GHC.Unit.Module (getModule)+import GHC.Unit.Module.ModIface (mi_fix)++import GHC.Types.Fixity.Env (lookupFixity)+import GHC.Iface.Load   (loadInterfaceForName)+import GHC.Types.Name+import GHC.Types.SrcLoc import GHC.Utils.Misc import GHC.Types.Var.Set++import GHC.Builtin.Names+import GHC.Builtin.Names.TH (liftClassKey)++import GHC.Utils.Outputable+import GHC.Utils.Panic+import GHC.Utils.Error  import Control.Monad.Trans.Reader import Data.Foldable (traverse_)
compiler/GHC/Tc/Errors.hs view
@@ -1,11 +1,11 @@  {-# LANGUAGE LambdaCase          #-} {-# LANGUAGE NamedFieldPuns      #-}+{-# LANGUAGE ParallelListComp    #-} {-# LANGUAGE ScopedTypeVariables #-}  {-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-} {-# OPTIONS_GHC -Wno-incomplete-record-updates #-}-{-# LANGUAGE ParallelListComp #-}  module GHC.Tc.Errors(        reportUnsolved, reportAllUnsolved, warnAllUnsolved,@@ -60,8 +60,7 @@ import GHC.Core.Predicate import GHC.Core.Type import GHC.Core.Coercion-import GHC.Core.TyCo.Ppr  ( pprTyVars-                           )+import GHC.Core.TyCo.Ppr     ( pprTyVars ) import GHC.Core.InstEnv import GHC.Core.TyCon import GHC.Core.DataCon@@ -672,7 +671,7 @@     is_user_type_error item _ = isUserTypeError (errorItemPred item)      is_homo_equality _ (EqPred _ ty1 ty2)-      = tcTypeKind ty1 `tcEqType` tcTypeKind ty2+      = typeKind ty1 `tcEqType` typeKind ty2     is_homo_equality _ _       = False @@ -1098,7 +1097,7 @@              -> do { -- See Note [Deferred errors for coercion holes]                      let co_var = coHoleCoVar hole                    ; addTcEvBind ev_binds_var $ mkWantedEvBind co_var err_tm-                   ; fillCoercionHole hole (mkTcCoVarCo co_var) } }+                   ; fillCoercionHole hole (mkCoVarCo co_var) } } addDeferredBinding _ _ _ = return ()    -- Do not set any evidence for Given  mkErrorTerm :: SolverReportErrCtxt -> CtLoc -> Type  -- of the error term@@ -1647,9 +1646,9 @@              -> ErrorItem              -> TcType -> TcType -> TcM (TcSolverReportMsg, [GhcHint]) mkEqErr_help ctxt item ty1 ty2-  | Just casted_tv1 <- tcGetCastedTyVar_maybe ty1+  | Just casted_tv1 <- getCastedTyVar_maybe ty1   = mkTyVarEqErr ctxt item casted_tv1 ty2-  | Just casted_tv2 <- tcGetCastedTyVar_maybe ty2+  | Just casted_tv2 <- getCastedTyVar_maybe ty2   = mkTyVarEqErr ctxt item casted_tv2 ty1   | otherwise   = do@@ -1803,7 +1802,7 @@   , Implic { ic_tclvl = lvl } <- implic   = assertPpr (not (isTouchableMetaTyVar lvl tv1))               (ppr tv1 $$ ppr lvl) $ do -- See Note [Error messages for untouchables]-    tv_extra     <- extraTyVarEqInfo (tv1, Just implic) ty2+    tv_extra <- extraTyVarEqInfo (tv1, Just implic) ty2     let tv_extra' = tv_extra { thisTyVarIsUntouchable = Just implic }         msg = Mismatch                { mismatchMsg           = mismatch_msg@@ -1969,7 +1968,7 @@           , thisTyVarIsUntouchable = mb_implic           , otherTy                = ty2_info }   where-    ty_extra ty = case tcGetCastedTyVar_maybe ty of+    ty_extra ty = case getCastedTyVar_maybe ty of                     Just (tv, _) -> Just <$> extraTyVarInfo tv                     Nothing      -> return Nothing @@ -1991,7 +1990,7 @@   = Nothing   where     inferred_bndrs =-      case tcGetTyVar_maybe ty1 of+      case getTyVar_maybe ty1 of         Just tv | isSkolemTyVar tv -> find (cec_encl ctxt) False tv         _                          -> [] @@ -2024,8 +2023,7 @@     KindEqOrigin cty1 cty2 sub_o mb_sub_t_or_k ->       (mkBasicMismatchMsg NoEA item ty1 ty2)         { mismatch_whenMatching = Just $ WhenMatching cty1 cty2 sub_o mb_sub_t_or_k-        , mismatch_mb_same_occ  = mb_same_occ-        }+        , mismatch_mb_same_occ  = mb_same_occ }     _ ->       (mkBasicMismatchMsg NoEA item ty1 ty2)         { mismatch_mb_same_occ  = mb_same_occ }
compiler/GHC/Tc/Errors/Hole.hs view
@@ -2,8 +2,6 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ExistentialQuantification #-} -{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}- module GHC.Tc.Errors.Hole    ( findValidHoleFits    , tcCheckHoleFit@@ -82,8 +80,7 @@ import GHC.Tc.Errors.Hole.FitTypes import qualified Data.Set as Set import GHC.Types.SrcLoc-import GHC.Utils.Trace (warnPprTrace)-import GHC.Data.FastString (unpackFS)+import GHC.Data.FastString (NonDetFastString(..)) import GHC.Types.Unique.Map  @@ -483,15 +480,16 @@      Just m  -> Right m      Nothing ->        Left $ case nameSrcLoc name of-         RealSrcLoc r _ -> unpackFS $ srcLocFile r-         UnhelpfulLoc s -> unpackFS $ s+         -- Nondeterminism is fine, this is used only to display a warning+         RealSrcLoc r _ -> NonDetFastString $ srcLocFile r+         UnhelpfulLoc s -> NonDetFastString s    report mods = do      { let warning =              text "WARNING: Couldn't find any documentation for the following modules:" $+$              nest 2-                  (pprWithCommas (either text ppr) (Set.toList mods) $+$+                  (pprWithCommas (either ppr ppr) (Set.toList mods) $+$                    text "Make sure the modules are compiled with '-haddock'.")-     ; warnPprTrace (not $ Set.null mods)"addHoleFitDocs" warning (pure ())+     ; warnPprTrace (not $ Set.null mods) "addHoleFitDocs" warning (pure ())      }  -- For pretty printing hole fits, we display the name and type of the fit,@@ -502,7 +500,7 @@ pprHoleFit (HFDC sWrp sWrpVars sTy sProv sMs) (HoleFit {..}) =  hang display 2 provenance  where tyApp = sep $ zipWithEqual "pprHoleFit" pprArg vars hfWrap-         where pprArg b arg = case binderArgFlag b of+         where pprArg b arg = case binderFlag b of                                 Specified -> text "@" <> pprParendType arg                                   -- Do not print type application for inferred                                   -- variables (#16456)@@ -520,11 +518,11 @@            -- e.g.            -- return :: forall (m :: * -> *) Monad m => (forall a . a -> m a)            -- into [m, a]-           unwrapTypeVars :: Type -> [TyCoVarBinder]+           unwrapTypeVars :: Type -> [ForAllTyBinder]            unwrapTypeVars t = vars ++ case splitFunTy_maybe unforalled of-                               Just (_, _, unfunned) -> unwrapTypeVars unfunned+                               Just (_, _, _, unfunned) -> unwrapTypeVars unfunned                                _ -> []-             where (vars, unforalled) = splitForAllTyCoVarBinders t+             where (vars, unforalled) = splitForAllForAllTyBinders t        holeVs = sep $ map (parens . (text "_" <+> dcolon <+>) . ppr) hfMatches        holeDisp = if sMs then holeVs                   else sep $ replicate (length hfMatches) $ text "_"@@ -917,7 +915,7 @@                                               _ -> True                             allConcrete = all notAbstract z_wrp_tys                       ; z_vars  <- zonkTcTyVars ref_vars-                      ; let z_mtvs = mapMaybe tcGetTyVar_maybe z_vars+                      ; let z_mtvs = mapMaybe getTyVar_maybe z_vars                       ; allFilled <- not <$> anyM isFlexiTyVar z_mtvs                       ; allowAbstract <- goptM Opt_AbstractRefHoleFits                       ; if allowAbstract || (allFilled && allConcrete )
compiler/GHC/Tc/Gen/App.hs view
@@ -6,8 +6,6 @@ {-# LANGUAGE TypeFamilies        #-} {-# LANGUAGE UndecidableInstances #-} -- Wrinkle in Note [Trees That Grow] -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}- {- % (c) The University of Glasgow 2006@@ -40,6 +38,7 @@ import GHC.Core.TyCo.Subst (substTyWithInScope) import GHC.Core.TyCo.FVs( shallowTyCoVarsOfType ) import GHC.Core.Type+import GHC.Core.Coercion import GHC.Tc.Types.Evidence import GHC.Types.Var.Set import GHC.Builtin.PrimOps( tagToEnumKey )@@ -544,7 +543,7 @@           HsUnboundVar {} -> True           _               -> False -    inst_all, inst_inferred, inst_none :: ArgFlag -> Bool+    inst_all, inst_inferred, inst_none :: ForAllTyFlag -> Bool     inst_all (Invisible {}) = True     inst_all Required       = False @@ -554,7 +553,7 @@      inst_none _ = False -    inst_fun :: [HsExprArg 'TcpRn] -> ArgFlag -> Bool+    inst_fun :: [HsExprArg 'TcpRn] -> ForAllTyFlag -> Bool     inst_fun [] | inst_final  = inst_all                 | otherwise   = inst_none                 -- Using `inst_none` for `:type` avoids@@ -573,7 +572,7 @@      -- go: If fun_ty=kappa, look it up in Theta     go delta acc so_far fun_ty args-      | Just kappa <- tcGetTyVar_maybe fun_ty+      | Just kappa <- getTyVar_maybe fun_ty       , kappa `elemVarSet` delta       = do { cts <- readMetaTyVar kappa            ; case cts of@@ -624,7 +623,7 @@      -- Rule IVAR from Fig 4 of the QL paper:     go1 delta acc so_far fun_ty args@(EValArg {} : _)-      | Just kappa <- tcGetTyVar_maybe fun_ty+      | Just kappa <- getTyVar_maybe fun_ty       , kappa `elemVarSet` delta       = -- Function type was of form   f :: forall a b. t1 -> t2 -> b         -- with 'b', one of the quantified type variables, in the corner@@ -651,8 +650,8 @@            ; let delta'  = delta `extendVarSetList` (res_nu:arg_nus)                  arg_tys = mkTyVarTys arg_nus                  res_ty  = mkTyVarTy res_nu-                 fun_ty' = mkVisFunTys (zipWithEqual "tcInstFun" mkScaled mults arg_tys) res_ty-                 co_wrap = mkWpCastN (mkTcGReflLeftCo Nominal fun_ty' kind_co)+                 fun_ty' = mkScaledFunTys (zipWithEqual "tcInstFun" mkScaled mults arg_tys) res_ty+                 co_wrap = mkWpCastN (mkGReflLeftCo Nominal fun_ty' kind_co)                  acc'    = addArgWrap co_wrap acc                  -- Suppose kappa :: kk                  -- Then fun_ty :: kk, fun_ty' :: Type, kind_co :: Type ~ kk@@ -716,7 +715,7 @@ -- The function type has already had its Inferred binders instantiated tcVTA fun_ty hs_ty   | Just (tvb, inner_ty) <- tcSplitForAllTyVarBinder_maybe fun_ty-  , binderArgFlag tvb == Specified+  , binderFlag tvb == Specified     -- It really can't be Inferred, because we've just     -- instantiated those. But, oddly, it might just be Required.     -- See Note [Required quantifiers in the type of a term]@@ -731,11 +730,12 @@              insted_ty = substTyWithInScope in_scope [tv] [ty_arg] inner_ty                          -- NB: tv and ty_arg have the same kind, so this                          --     substitution is kind-respecting-       ; traceTc "VTA" (vcat [ppr tv, debugPprType kind-                             , debugPprType ty_arg-                             , debugPprType (tcTypeKind ty_arg)-                             , debugPprType inner_ty-                             , debugPprType insted_ty ])+       ; traceTc "VTA" (vcat [ text "fun_ty" <+> ppr fun_ty+                             , text "tv" <+> ppr tv <+> dcolon <+> debugPprType kind+                             , text "ty_arg" <+> debugPprType ty_arg <+> dcolon+                                             <+> debugPprType (typeKind ty_arg)+                             , text "inner_ty" <+> debugPprType inner_ty+                             , text "insted_ty" <+> debugPprType insted_ty ])        ; return (ty_arg, insted_ty) }    | otherwise@@ -758,7 +758,7 @@ We want to reject this type application to Int, but in earlier GHCs we had an ASSERT that Required could not occur here. -The ice is thin; c.f. Note [No Required TyCoBinder in terms]+The ice is thin; c.f. Note [No Required PiTyBinder in terms] in GHC.Core.TyCo.Rep.  Note [VTA for out-of-scope functions]@@ -876,7 +876,7 @@               -- This top-level zonk step, which is the reason               -- we need a local 'go' loop, is subtle               -- See Section 9 of the QL paper-              | Just kappa <- tcGetTyVar_maybe arg_ty+              | Just kappa <- getTyVar_maybe arg_ty               , kappa `elemVarSet` delta               = do { info <- readMetaTyVar kappa                    ; case info of@@ -990,8 +990,8 @@      -- Now, and only now, expand synonyms     go bvs rho1 rho2-      | Just rho1 <- tcView rho1 = go bvs rho1 rho2-      | Just rho2 <- tcView rho2 = go bvs rho1 rho2+      | Just rho1 <- coreView rho1 = go bvs rho1 rho2+      | Just rho2 <- coreView rho2 = go bvs rho1 rho2      go bvs (TyConApp tc1 tys1) (TyConApp tc2 tys2)       | tc1 == tc2@@ -1001,25 +1001,25 @@      -- Decompose (arg1 -> res1) ~ (arg2 -> res2)     -- and         (c1 => res1) ~   (c2 => res2)-    -- But for the latter we only learn instantiation info from t1~t2+    -- But for the latter we only learn instantiation info from res1~res2     -- We look at the multiplicity too, although the chances of getting     -- impredicative instantiation info from there seems...remote.     go bvs (FunTy { ft_af = af1, ft_arg = arg1, ft_res = res1, ft_mult = mult1 })            (FunTy { ft_af = af2, ft_arg = arg2, ft_res = res2, ft_mult = mult2 })-      | af1 == af2-      = do { when (af1 == VisArg) $-             do { go bvs arg1 arg2; go bvs mult1 mult2 }+      | af1 == af2 -- Match the arrow TyCon+      = do { when (isVisibleFunArg af1) (go bvs arg1 arg2)+           ; when (isFUNArg af1)        (go bvs mult1 mult2)            ; go bvs res1 res2 }      -- ToDo: c.f. Tc.Utils.unify.uType,     -- which does not split FunTy here-    -- Also NB tcRepSplitAppTy here, which does not split (c => t)+    -- Also NB tcSplitAppTyNoView here, which does not split (c => t)     go bvs (AppTy t1a t1b) ty2-      | Just (t2a, t2b) <- tcRepSplitAppTy_maybe ty2+      | Just (t2a, t2b) <- tcSplitAppTyNoView_maybe ty2       = do { go bvs t1a t2a; go bvs t1b t2b }      go bvs ty1 (AppTy t2a t2b)-      | Just (t1a, t1b) <- tcRepSplitAppTy_maybe ty1+      | Just (t1a, t1b) <- tcSplitAppTyNoView_maybe ty1       = do { go bvs t1a t2a; go bvs t1b t2b }      go (bvs1, bvs2) (ForAllTy bv1 ty1) (ForAllTy bv2 ty2)@@ -1215,7 +1215,7 @@          check_enumeration res_ty rep_tc        ; let rep_ty  = mkTyConApp rep_tc rep_args              tc_fun' = mkHsWrap (WpTyApp rep_ty) tc_fun-             df_wrap = mkWpCastR (mkTcSymCo coi)+             df_wrap = mkWpCastR (mkSymCo coi)        ; tc_expr <- rebuildHsApps tc_fun' fun_ctxt [val_arg] res_ty        ; return (mkHsWrap df_wrap tc_expr) }}}}} 
compiler/GHC/Tc/Gen/Arrow.hs view
@@ -33,6 +33,7 @@ import GHC.Tc.Types.Origin import GHC.Tc.Types.Evidence import GHC.Core.Multiplicity+import GHC.Core.Coercion import GHC.Types.Id( mkLocalId ) import GHC.Tc.Utils.Instantiate import GHC.Builtin.Types@@ -104,8 +105,7 @@         ; (pat', cmd') <- newArrowScope                           $ tcCheckPat (ArrowMatchCtxt ProcExpr) pat (unrestricted arg_ty)                           $ tcCmdTop cmd_env names' cmd (unitTy, res_ty)-        ; let res_co = mkTcTransCo co-                         (mkTcAppCo co1 (mkTcNomReflCo res_ty))+        ; let res_co = co `mkTransCo` mkAppCo co1 (mkNomReflCo res_ty)         ; return (pat', cmd', res_co) }  {-@@ -383,11 +383,11 @@  matchExpectedCmdArgs :: Arity -> TcType -> TcM (TcCoercionN, [TcTypeFRR], TcType) matchExpectedCmdArgs 0 ty-  = return (mkTcNomReflCo ty, [], ty)+  = return (mkNomReflCo ty, [], ty) matchExpectedCmdArgs n ty   = do { (co1, [ty1, ty2]) <- matchExpectedTyConApp pairTyCon ty        ; (co2, tys, res_ty) <- matchExpectedCmdArgs (n-1) ty2-       ; return (mkTcTyConAppCo Nominal pairTyCon [co1, co2], ty1:tys, res_ty) }+       ; return (mkTyConAppCo Nominal pairTyCon [co1, co2], ty1:tys, res_ty) }  {- ************************************************************************@@ -424,7 +424,8 @@                             , recS_rec_ids = rec_names }) res_ty thing_inside   = do  { let tup_names = rec_names ++ filterOut (`elem` rec_names) later_names         ; tup_elt_tys <- newFlexiTyVarTys (length tup_names) liftedTypeKind-        ; let tup_ids = zipWith (\n p -> mkLocalId n Many p) tup_names tup_elt_tys -- Many because it's a recursive definition+        ; let tup_ids = zipWith (\n p -> mkLocalId n ManyTy p) tup_names tup_elt_tys+                        -- Many because it's a recursive definition         ; tcExtendIdEnv tup_ids $ do         { (stmts', tup_rets)                 <- tcStmtsAndThen ctxt (tcArrDoStmt env) stmts res_ty   $ \ _res_ty' ->
compiler/GHC/Tc/Gen/Bind.hs view
@@ -32,6 +32,7 @@ import GHC.Driver.Session import GHC.Data.FastString import GHC.Hs+ import GHC.Tc.Errors.Types import GHC.Tc.Gen.Sig import GHC.Tc.Utils.Concrete ( hasFixedRuntimeRep_syntactic )@@ -42,46 +43,53 @@ import GHC.Tc.Solver import GHC.Tc.Types.Evidence import GHC.Tc.Types.Constraint-import GHC.Core.Predicate-import GHC.Core.TyCo.Ppr( pprTyVars )+ import GHC.Tc.Gen.HsType import GHC.Tc.Gen.Pat import GHC.Tc.Utils.TcMType+import GHC.Tc.Instance.Family( tcGetFamInstEnvs )+import GHC.Tc.Utils.TcType+import GHC.Tc.Validity (checkValidType)++import GHC.Core.Predicate import GHC.Core.Reduction ( Reduction(..) ) import GHC.Core.Multiplicity import GHC.Core.FamInstEnv( normaliseType )-import GHC.Tc.Instance.Family( tcGetFamInstEnvs ) import GHC.Core.Class   ( Class )-import GHC.Tc.Utils.TcType+import GHC.Core.Coercion( mkSymCo ) import GHC.Core.Type (mkStrLitTy, tidyOpenType, mkCastTy)-import GHC.Builtin.Types ( mkBoxedTupleTy )+import GHC.Core.TyCo.Ppr( pprTyVars )++import GHC.Builtin.Types ( mkConstraintTupleTy ) import GHC.Builtin.Types.Prim+import GHC.Unit.Module+ import GHC.Types.SourceText import GHC.Types.Id import GHC.Types.Var as Var import GHC.Types.Var.Set import GHC.Types.Var.Env( TidyEnv, TyVarEnv, mkVarEnv, lookupVarEnv )-import GHC.Unit.Module import GHC.Types.Name import GHC.Types.Name.Set import GHC.Types.Name.Env import GHC.Types.SrcLoc-import GHC.Data.Bag+ import GHC.Utils.Error-import GHC.Data.Graph.Directed-import GHC.Data.Maybe import GHC.Utils.Misc import GHC.Types.Basic import GHC.Types.CompleteMatch import GHC.Utils.Outputable as Outputable import GHC.Utils.Panic import GHC.Builtin.Names( ipClassName )-import GHC.Tc.Validity (checkValidType) import GHC.Types.Unique.FM import GHC.Types.Unique.DSet import GHC.Types.Unique.Set import qualified GHC.LanguageExtensions as LangExt +import GHC.Data.Bag+import GHC.Data.Graph.Directed+import GHC.Data.Maybe+ import Control.Monad import Data.Foldable (find) @@ -540,7 +548,7 @@       , Just poly_id <- completeSigPolyId_maybe sig       = poly_id       | otherwise-      = mkLocalId name Many forall_a_a+      = mkLocalId name ManyTy forall_a_a  forall_a_a :: TcType -- At one point I had (forall r (a :: TYPE r). a), but of course@@ -667,7 +675,7 @@           = sl_fs $ unLoc cc_str           | otherwise           = getOccFS (Var.varName fun_id)-        cc_name = moduleNameFS (moduleName mod) `appendFS` consFS '.' cc_str+        cc_name = concatFS [moduleNameFS (moduleName mod), fsLit ".", cc_str]   = do       flavour <- DeclCC <$> getCCIndexTcM cc_name       let cc = mkUserCC cc_name mod loc flavour@@ -904,7 +912,7 @@          -- do this check; otherwise (#14000) we may report an ambiguity          -- error for a rather bogus type. -       ; return (mkLocalId poly_name Many inferred_poly_ty) }+       ; return (mkLocalId poly_name ManyTy inferred_poly_ty) }   chooseInferredQuantifiers :: WantedConstraints  -- residual constraints@@ -1006,12 +1014,12 @@            -- NB: my_theta already includes all the annotated constraints            ; diff_theta <- findInferredDiff annotated_theta my_theta -           ; case tcGetCastedTyVar_maybe wc_var_ty of+           ; case getCastedTyVar_maybe wc_var_ty of                -- We know that wc_co must have type kind(wc_var) ~ Constraint, as it                -- comes from the checkExpectedKind in GHC.Tc.Gen.HsType.tcAnonWildCardOcc.                -- So, to make the kinds work out, we reverse the cast here.-               Just (wc_var, wc_co) -> writeMetaTyVar wc_var (mk_ctuple diff_theta-                                                              `mkCastTy` mkTcSymCo wc_co)+               Just (wc_var, wc_co) -> writeMetaTyVar wc_var (mkConstraintTupleTy diff_theta+                                                              `mkCastTy` mkSymCo wc_co)                Nothing              -> pprPanic "chooseInferredQuantifiers 1" (ppr wc_var_ty)             ; traceTc "completeTheta" $@@ -1037,13 +1045,9 @@                       , residual_ct <- bagToList $ wc_simple (ic_wanted residual_implic)                       , let residual_pred = ctPred residual_ct                       , Just (Nominal, lhs, rhs) <- [ getEqPredTys_maybe residual_pred ]-                      , Just lhs_tv <- [ tcGetTyVar_maybe lhs ]+                      , Just lhs_tv <- [ getTyVar_maybe lhs ]                       , lhs_tv == tv ] -    mk_ctuple preds = mkBoxedTupleTy preds-       -- Hack alert!  See GHC.Tc.Gen.HsType:-       -- Note [Extra-constraint holes in partial type signatures]- chooseInferredQuantifiers _ _ _ _ (Just (TISI { sig_inst_sig = sig@(CompleteSig {}) }))   = pprPanic "chooseInferredQuantifiers" (ppr sig) @@ -1261,7 +1265,7 @@   = setSrcSpanA b_loc    $     do  { ((co_fn, matches'), mono_id, _) <- fixM $ \ ~(_, _, rhs_ty) ->                                           -- See Note [fixM for rhs_ty in tcMonoBinds]-            do  { mono_id <- newLetBndr no_gen name Many rhs_ty+            do  { mono_id <- newLetBndr no_gen name ManyTy rhs_ty                 ; (matches', rhs_ty')                     <- tcInfer $ \ exp_ty ->                        tcExtendBinderStack [TcIdBndr_ExpType name exp_ty NotTopLevel] $@@ -1441,7 +1445,7 @@    | otherwise  -- No type signature   = do { mono_ty <- newOpenFlexiTyVarTy-       ; mono_id <- newLetBndr no_gen name Many mono_ty+       ; mono_id <- newLetBndr no_gen name ManyTy mono_ty           -- This ^ generates a binder with Many multiplicity because all           -- let/where-binders are unrestricted. When we introduce linear let           -- binders, we will need to retrieve the multiplicity information.@@ -1512,7 +1516,7 @@   | CompleteSig { sig_bndr = poly_id } <- id_sig   = addInlinePrags poly_id (lookupPragEnv prags name) newSigLetBndr no_gen name (TISI { sig_inst_tau = tau })-  = newLetBndr no_gen name Many tau+  = newLetBndr no_gen name ManyTy tau     -- Binders with a signature are currently always of multiplicity     -- Many. Because they come either from toplevel, let, or where     -- declarations. Which are all unrestricted currently.
compiler/GHC/Tc/Gen/Default.hs view
@@ -12,7 +12,8 @@  import GHC.Hs import GHC.Core.Class-import GHC.Core.Type ( typeKind )+import GHC.Core.Type( typeKind )+ import GHC.Types.Var( tyVarKind ) import GHC.Tc.Errors.Types import GHC.Tc.Utils.Monad
compiler/GHC/Tc/Gen/Expr.hs view
@@ -69,6 +69,7 @@ import GHC.Types.Name.Reader import GHC.Core.TyCon import GHC.Core.Type+import GHC.Core.Coercion( mkSymCo ) import GHC.Tc.Types.Evidence import GHC.Builtin.Types import GHC.Builtin.Names@@ -331,7 +332,7 @@               -- See Note [Typechecking data constructors] in GHC.Tc.Gen.Head              -- See Note [Don't flatten tuples from HsSyn] in GHC.Core.Make-             act_res_ty = mkVisFunTys missing_tys (mkTupleTy1 boxity arg_tys)+             act_res_ty = mkScaledFunTys missing_tys (mkTupleTy1 boxity arg_tys)         ; traceTc "ExplicitTuple" (ppr act_res_ty $$ ppr res_ty) @@ -648,7 +649,7 @@ arithSeqEltType Nothing res_ty   = do { res_ty <- expTypeToType res_ty        ; (coi, elt_ty) <- matchExpectedListTy res_ty-       ; return (mkWpCastN coi, One, elt_ty, Nothing) }+       ; return (mkWpCastN coi, OneTy, elt_ty, Nothing) } arithSeqEltType (Just fl) res_ty   = do { ((elt_mult, elt_ty), fl')            <- tcSyntaxOp ListOrigin fl [SynList] res_ty $@@ -847,7 +848,7 @@            ; (list_co, elt_ty)   <- matchExpectedListTy rho_ty                -- list_co :: [elt_ty] ~N rho_ty            ; result <- thing_inside [elt_ty]-           ; return (result, mkWpCastN (mkTcSymCo list_co) <.> inst_wrap) }+           ; return (result, mkWpCastN (mkSymCo list_co) <.> inst_wrap) }     tc_syn_arg _ (SynFun {}) _       = pprPanic "tcSynArgA hits a SynFun" (ppr orig)     tc_syn_arg res_ty (SynType the_ty) thing_inside@@ -1182,8 +1183,8 @@           -- the record to disambiguate its fields, so we must infer the record           -- type here before we can desugar. See Wrinkle [Disambiguating fields]           -- in Note [Record Updates].-       ; ((_, record_rho), _lie) <- captureConstraints $  -- see (1) below-                                    tcScalingUsage Many $ -- see (2) below+       ; ((_, record_rho), _lie) <- captureConstraints    $ -- see (1) below+                                    tcScalingUsage ManyTy $ -- see (2) below                                     tcInferRho record_expr              -- (1)@@ -1593,7 +1594,7 @@                 field_ty            ; let field_id = mkUserLocal (nameOccName sel_name)                                         (nameUnique sel_name)-                                        Many field_ty (locA loc)+                                        ManyTy field_ty (locA loc)                 -- Yuk: the field_id has the *unique* of the selector Id                 --          (so we can find it easily)                 --      but is a LocalId with the appropriate type of the RHS
compiler/GHC/Tc/Gen/Foreign.hs view
@@ -44,29 +44,35 @@ import GHC.Tc.Gen.HsType import GHC.Tc.Gen.Expr import GHC.Tc.Utils.Env-+import GHC.Tc.Utils.TcType import GHC.Tc.Instance.Family+ import GHC.Core.FamInstEnv import GHC.Core.Coercion import GHC.Core.Reduction import GHC.Core.Type import GHC.Core.Multiplicity+import GHC.Core.DataCon+import GHC.Core.TyCon+import GHC.Core.TyCon.RecWalk+ import GHC.Types.ForeignCall-import GHC.Utils.Error import GHC.Types.Id import GHC.Types.Name import GHC.Types.Name.Reader-import GHC.Core.DataCon-import GHC.Core.TyCon-import GHC.Core.TyCon.RecWalk-import GHC.Tc.Utils.TcType+import GHC.Types.SrcLoc+ import GHC.Builtin.Names+import GHC.Builtin.Types.Prim( isArrowTyCon )+ import GHC.Driver.Session import GHC.Driver.Backend++import GHC.Utils.Error import GHC.Utils.Outputable as Outputable import GHC.Utils.Panic import GHC.Platform-import GHC.Types.SrcLoc+ import GHC.Data.Bag import GHC.Driver.Hooks import qualified GHC.LanguageExtensions as LangExt@@ -122,13 +128,13 @@   where     go :: Role -> RecTcChecker -> Type -> WriterT (Bag GlobalRdrElt) TcM Reduction     go role rec_nts ty-      | Just ty' <- tcView ty     -- Expand synonyms+      | Just ty' <- coreView ty     -- Expand synonyms       = go role rec_nts ty'        | Just (tc, tys) <- splitTyConApp_maybe ty       = go_tc_app role rec_nts tc tys -      | (bndrs, inner_ty) <- splitForAllTyCoVarBinders ty+      | (bndrs, inner_ty) <- splitForAllForAllTyBinders ty       , not (null bndrs)       = do redn <- go role rec_nts inner_ty            return $ mkHomoForAllRedn bndrs redn@@ -139,9 +145,13 @@     go_tc_app :: Role -> RecTcChecker -> TyCon -> [Type]               -> WriterT (Bag GlobalRdrElt) TcM Reduction     go_tc_app role rec_nts tc tys+        | isArrowTyCon tc  -- Recurse through arrows, or at least the top+        = children_only    -- level arrows.  Remember, the default case is+                           -- "don't recurse" (see last eqn for go_tc_app)++        | tc_key `elem` [ioTyConKey, funPtrTyConKey]         -- We don't want to look through the IO newtype, even if it is         -- in scope, so we have a special case for it:-        | tc_key `elem` [ioTyConKey, funPtrTyConKey, funTyConKey]         = children_only          | isNewTyCon tc         -- Expand newtypes@@ -173,7 +183,7 @@           children_only             = do { args <- unzipRedns <$>                             zipWithM ( \ ty r -> go r rec_nts ty )-                                     tys (tyConRolesX role tc)+                                     tys (tyConRoleListX role tc)                  ; return $ mkTyConAppRedn role tc args }           nt_co  = mkUnbranchedAxInstCo role (newTyConCo tc) tys []           nt_rhs = newTyConInstRhs tc tys@@ -244,10 +254,17 @@     do { sig_ty <- tcHsSigType (ForSigCtxt nm) hs_ty        ; (Reduction norm_co norm_sig_ty, gres) <- normaliseFfiType sig_ty        ; let-           -- Drop the foralls before inspecting the-           -- structure of the foreign type.-             (arg_tys, res_ty) = tcSplitFunTys (dropForAlls norm_sig_ty)-             id                = mkLocalId nm Many sig_ty+             -- Drop the foralls before inspecting the+             -- structure of the foreign type.+             -- Use splitFunTys, which splits (=>) as well as (->)+             -- so that for  foreign import foo :: Eq a => a -> blah+             -- we get "unacceptable argument Eq a" rather than+             --        "unacceptable result Eq a => a -> blah"+             -- Not a big deal.  We could make a better error message specially+             -- for overloaded functions, but doesn't seem worth it+             (arg_tys, res_ty) = splitFunTys (dropForAlls norm_sig_ty)++             id = mkLocalId nm ManyTy sig_ty                  -- Use a LocalId to obey the invariant that locally-defined                  -- things are LocalIds.  However, it does not need zonking,                  -- (so GHC.Tc.Utils.Zonk.zonkForeignExports ignores it).@@ -271,7 +288,7 @@   = do checkCg (Right idecl) backendValidityOfCImport        -- NB check res_ty not sig_ty!        --    In case sig_ty is (forall a. ForeignPtr a)-       check (isFFILabelTy (mkVisFunTys arg_tys res_ty))+       check (isFFILabelTy (mkScaledFunTys arg_tys res_ty))              (TcRnIllegalForeignType Nothing)        cconv' <- checkCConv (Right idecl) cconv        return (CImport src (L lc cconv') safety mh l)@@ -304,7 +321,7 @@           addErrTc (TcRnIllegalForeignType Nothing AtLeastOneArgExpected)         (Scaled arg1_mult arg1_ty:arg_tys) -> do           dflags <- getDynFlags-          let curried_res_ty = mkVisFunTys arg_tys res_ty+          let curried_res_ty = mkScaledFunTys arg_tys res_ty           checkNoLinearFFI arg1_mult           check (isFFIDynTy curried_res_ty arg1_ty)                 (TcRnIllegalForeignType (Just Arg))@@ -323,6 +340,10 @@       -- prim import result is more liberal, allows (#,,#)       checkForeignRes nonIOok checkSafe (isFFIPrimResultTy dflags) res_ty       return (CImport src (L lc cconv) (L ls safety) mh (CFunction target))+  | cconv == JavaScriptCallConv = do+      checkCg (Right idecl) backendValidityOfCImport+      -- leave the rest to the JS backend (at least for now)+      return (CImport src (L lc cconv) (L ls safety) mh (CFunction target))   | otherwise = do              -- Normal foreign import       checkCg (Right idecl) backendValidityOfCImport       cconv' <- checkCConv (Right idecl) cconv@@ -442,8 +463,8 @@                           check (pred ty) (TcRnIllegalForeignType (Just Arg))  checkNoLinearFFI :: Mult -> TcM ()  -- No linear types in FFI (#18472)-checkNoLinearFFI Many = return ()-checkNoLinearFFI _    = addErrTc $ TcRnIllegalForeignType (Just Arg)+checkNoLinearFFI ManyTy = return ()+checkNoLinearFFI _      = addErrTc $ TcRnIllegalForeignType (Just Arg)                                    LinearTypesNotAllowed  ------------ Checking result types for foreign calls ----------------------@@ -464,7 +485,7 @@    -- We disallow nested foralls in foreign types   -- (at least, for the time being). See #16702.-  | tcIsForAllTy ty+  | isForAllTy ty   = addErrTc $ TcRnIllegalForeignType (Just Result) UnexpectedNestedForall    -- Case for non-IO result type with FFI Import
compiler/GHC/Tc/Gen/Head.hs view
@@ -9,8 +9,6 @@ {-# LANGUAGE ViewPatterns        #-} {-# LANGUAGE DisambiguateRecordFields #-} -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}- {- % (c) The University of Glasgow 2006@@ -35,20 +33,20 @@  import {-# SOURCE #-} GHC.Tc.Gen.Expr( tcExpr, tcCheckMonoExprNC, tcCheckPolyExprNC ) +import GHC.Prelude+import GHC.Hs+ import GHC.Tc.Gen.HsType+import GHC.Rename.Unbound     ( unknownNameSuggestions, WhatLooking(..) )+ import GHC.Tc.Gen.Bind( chooseInferredQuantifiers ) import GHC.Tc.Gen.Sig( tcUserTypeSig, tcInstSig, lhsSigWcTypeContextSpan ) import GHC.Tc.TyCl.PatSyn( patSynBuilderOcc ) import GHC.Tc.Utils.Monad import GHC.Tc.Utils.Unify-import GHC.Types.Basic-import GHC.Types.Error import GHC.Tc.Utils.Concrete ( hasFixedRuntimeRep_syntactic ) import GHC.Tc.Utils.Instantiate import GHC.Tc.Instance.Family ( tcLookupDataFamInst )-import GHC.Core.FamInstEnv    ( FamInstEnvs )-import GHC.Core.UsageEnv      ( unitUE )-import GHC.Rename.Unbound     ( unknownNameSuggestions, WhatLooking(..) ) import GHC.Unit.Module        ( getModule ) import GHC.Tc.Errors.Types import GHC.Tc.Solver          ( InferMode(..), simplifyInfer )@@ -56,37 +54,43 @@ import GHC.Tc.Utils.TcMType import GHC.Tc.Types.Origin import GHC.Tc.Utils.TcType as TcType-import GHC.Hs+import GHC.Tc.Types.Evidence import GHC.Hs.Syn.Type-import GHC.Types.Id-import GHC.Types.Id.Info++import GHC.Core.FamInstEnv    ( FamInstEnvs )+import GHC.Core.UsageEnv      ( unitUE ) import GHC.Core.PatSyn( PatSyn ) import GHC.Core.ConLike( ConLike(..) ) import GHC.Core.DataCon-import GHC.Types.Name-import GHC.Types.Name.Reader import GHC.Core.TyCon import GHC.Core.TyCo.Rep import GHC.Core.Type-import GHC.Tc.Types.Evidence++import GHC.Types.Var( isInvisibleFunArg )+import GHC.Types.Id+import GHC.Types.Id.Info+import GHC.Types.Name+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc+import GHC.Types.Basic+import GHC.Types.Error+ import GHC.Builtin.Types( multiplicityTy ) import GHC.Builtin.Names import GHC.Builtin.Names.TH( liftStringName, liftName )+ import GHC.Driver.Env import GHC.Driver.Session-import GHC.Types.SrcLoc import GHC.Utils.Misc-import GHC.Data.Maybe import GHC.Utils.Outputable as Outputable import GHC.Utils.Panic import GHC.Utils.Panic.Plain++import GHC.Data.Maybe import Control.Monad -import Data.Function -import GHC.Prelude - {- ********************************************************************* *                                                                      *               HsExprArg: auxiliary data type@@ -591,7 +595,7 @@        where -      rem_arg_tys :: [(Scaled Type, AnonArgFlag)]+      rem_arg_tys :: [(Scaled Type, FunTyFlag)]       rem_arg_tys = getRuntimeArgTys app_res_rho         -- We do not need to zonk app_res_rho first, because the number of arrows         -- in the (possibly instantiated) inferred type of the function will@@ -606,7 +610,7 @@                      -- value argument index, starting from 1                      -- used to count up to the arity to ensure that                      -- we don't check too many argument types-                  -> [(Scaled Type, AnonArgFlag)]+                  -> [(Scaled Type, FunTyFlag)]                      -- run-time argument types                   -> TcM ()       tc_rem_args _ i_val _@@ -617,9 +621,9 @@         -- than the number of arguments apparent from the type.         = pprPanic "tcRemainingValArgs" debug_msg       tc_rem_args i_visval !i_val ((Scaled _ arg_ty, af) : tys)-        = do { let (i_visval', arg_pos) =-                     case af of { InvisArg -> ( i_visval    , ArgPosInvis )-                                ; VisArg   -> ( i_visval + 1, ArgPosVis i_visval ) }+        = do { let (i_visval', arg_pos)+                     | isInvisibleFunArg af = ( i_visval    , ArgPosInvis )+                     | otherwise            = ( i_visval + 1, ArgPosVis i_visval )                    frr_ctxt = FRRNoBindingResArg rep_poly_fun arg_pos              ; hasFixedRuntimeRep_syntactic frr_ctxt arg_ty                  -- Why is this a syntactic check? See Wrinkle [Syntactic check] in@@ -948,7 +952,7 @@        ; traceTc "tcExpSig" (ppr qtvs $$ ppr givens $$ ppr inferred_sigma $$ ppr my_sigma)        ; let poly_wrap = wrap                          <.> mkWpTyLams qtvs-                         <.> mkWpLams givens+                         <.> mkWpEvLams givens                          <.> mkWpLet  ev_binds        ; return (mkLHsWrap poly_wrap expr', my_sigma) } @@ -1118,7 +1122,7 @@ check_local_id :: Id -> TcM () check_local_id id   = do { checkThLocalId id-       ; tcEmitBindingUsage $ unitUE (idName id) One }+       ; tcEmitBindingUsage $ unitUE (idName id) OneTy }  check_naughty :: OccName -> TcId -> TcM () check_naughty lbl id@@ -1147,14 +1151,14 @@         ; return ( XExpr (ConLikeTc (RealDataCon con) tvs all_arg_tys)                 , mkInvisForAllTys tvbs $ mkPhiTy full_theta $-                  mkVisFunTys scaled_arg_tys res ) }+                  mkScaledFunTys scaled_arg_tys res ) }   where     linear_to_poly :: Scaled Type -> TcM (Scaled Type)     -- linear_to_poly implements point (3,4)     -- of Note [Typechecking data constructors]-    linear_to_poly (Scaled One ty) = do { mul_var <- newFlexiTyVarTy multiplicityTy-                                        ; return (Scaled mul_var ty) }-    linear_to_poly scaled_ty       = return scaled_ty+    linear_to_poly (Scaled OneTy ty) = do { mul_var <- newFlexiTyVarTy multiplicityTy+                                          ; return (Scaled mul_var ty) }+    linear_to_poly scaled_ty         = return scaled_ty  tcInferPatSyn :: Name -> PatSyn -> TcM (HsExpr GhcTc, TcSigmaType) tcInferPatSyn id_name ps
compiler/GHC/Tc/Gen/HsType.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE DataKinds           #-} {-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE MonadComprehensions #-} {-# LANGUAGE RankNTypes          #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies        #-}@@ -82,7 +83,6 @@ import GHC.Tc.Errors.Types import GHC.Tc.Utils.Monad import GHC.Tc.Types.Origin-import GHC.Core.Predicate import GHC.Tc.Types.Constraint import GHC.Tc.Utils.Env import GHC.Tc.Utils.TcMType@@ -91,13 +91,16 @@ import GHC.IfaceToCore import GHC.Tc.Solver import GHC.Tc.Utils.Zonk-import GHC.Core.TyCo.Rep-import GHC.Core.TyCo.Ppr import GHC.Tc.Utils.TcType import GHC.Tc.Utils.Instantiate ( tcInstInvisibleTyBinders, tcInstInvisibleTyBindersN,                                   tcInstInvisibleTyBinder, tcSkolemiseInvisibleBndrs,                                   tcInstTypeBndrs )+ import GHC.Core.Type+import GHC.Core.Predicate+import GHC.Core.TyCo.Rep+import GHC.Core.TyCo.Ppr+ import GHC.Builtin.Types.Prim import GHC.Types.Error import GHC.Types.Name.Env@@ -125,6 +128,8 @@ import qualified GHC.LanguageExtensions as LangExt  import GHC.Data.FastString+import GHC.Data.List.Infinite ( Infinite (..) )+import qualified GHC.Data.List.Infinite as Inf import GHC.Data.List.SetOps import GHC.Data.Maybe import GHC.Data.Bag( unitBag )@@ -632,7 +637,7 @@ tcHsDeriv hs_ty   = do { ty <- tcTopLHsType DerivClauseCtxt hs_ty        ; let (tvs, pred)    = splitForAllTyCoVars ty-             (kind_args, _) = splitFunTys (tcTypeKind pred)+             (kind_args, _) = splitFunTys (typeKind pred)        ; case getClassPredTys_maybe pred of            Just (cls, tys) -> return (tvs, cls, tys, map scaledThing kind_args)            Nothing -> failWithTc $ TcRnIllegalDerivingItem hs_ty }@@ -1044,7 +1049,7 @@ -- -- See Note [Delaying modFinalizers in untyped splices]. tc_infer_hs_type mode (HsSpliceTy (HsUntypedSpliceTop _ ty) _)-  = tc_infer_hs_type mode ty+  = tc_infer_lhs_type mode ty  tc_infer_hs_type _ (HsSpliceTy (HsUntypedSpliceNested n) s) = pprPanic "tc_infer_hs_type: invalid nested splice" (pprUntypedSplice True (Just n) s) @@ -1061,7 +1066,7 @@                      (mkInScopeSetList $ map snd subst_prs)                      (listToUFM_Directly $ map (fmap mkTyVarTy) subst_prs)            ty' = substTy subst ty-       return (ty', tcTypeKind ty')+       return (ty', typeKind ty')  tc_infer_hs_type _ (HsExplicitListTy _ _ tys)   | null tys  -- this is so that we can use visible kind application with '[]@@ -1148,7 +1153,7 @@ tc_hs_type mode (HsSpliceTy (HsUntypedSpliceTop mod_finalizers ty) _)            exp_kind   = do addModFinalizersWithLclEnv mod_finalizers-       tc_hs_type mode ty exp_kind+       tc_lhs_type mode ty exp_kind  tc_hs_type _ (HsSpliceTy (HsUntypedSpliceNested n) s) _ = pprPanic "tc_hs_type: invalid nested splice" (pprUntypedSplice True (Just n) s) @@ -1157,7 +1162,7 @@   = tc_fun_type mode mult ty1 ty2 exp_kind  tc_hs_type mode (HsOpTy _ _ ty1 (L _ op) ty2) exp_kind-  | op `hasKey` funTyConKey+  | op `hasKey` unrestrictedFunTyConKey   = tc_fun_type mode (HsUnrestrictedArrow noHsUniTok) ty1 ty2 exp_kind  --------- Foralls@@ -1178,10 +1183,10 @@   = tc_lhs_type mode rn_ty exp_kind    -- See Note [Body kind of a HsQualTy]-  | tcIsConstraintKind exp_kind+  | isConstraintLikeKind exp_kind   = do { ctxt' <- tc_hs_context mode ctxt        ; ty'   <- tc_lhs_type mode rn_ty constraintKind-       ; return (mkPhiTy ctxt' ty') }+       ; return (tcMkDFunPhiTy ctxt' ty') }    | otherwise   = do { ctxt' <- tc_hs_context mode ctxt@@ -1189,7 +1194,7 @@        ; ek <- newOpenTypeKind  -- The body kind (result of the function) can                                 -- be TYPE r, for any r, hence newOpenTypeKind        ; ty' <- tc_lhs_type mode rn_ty ek-       ; checkExpectedKind (unLoc rn_ty) (mkPhiTy ctxt' ty')+       ; checkExpectedKind (unLoc rn_ty) (tcMkPhiTy ctxt' ty')                            liftedTypeKind exp_kind }  --------- Lists, arrays, and tuples@@ -1275,8 +1280,8 @@                            constraintKind exp_kind }  tc_hs_type _ rn_ty@(HsStarTy _ _) exp_kind-  -- Desugaring 'HsStarTy' to 'Data.Kind.Type' here means that we don't have to-  -- handle it in 'coreView' and 'tcView'.+  -- Desugaring 'HsStarTy' to 'Data.Kind.Type' here means that we don't+  -- have to handle it in 'coreView'   = checkExpectedKind rn_ty liftedTypeKind liftedTypeKind exp_kind  --------- Literals@@ -1310,12 +1315,12 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A HsForAllTy contains an HsForAllTelescope to denote the visibility of the forall binder. Furthermore, each invisible type variable binder also has a-Specificity. Together, these determine the variable binders (ArgFlag) for each+Specificity. Together, these determine the variable binders (ForAllTyFlag) for each variable in the generated ForAllTy type.  This table summarises this relation: -----------------------------------------------------------------------------| User-written type         HsForAllTelescope   Specificity        ArgFlag+| User-written type         HsForAllTelescope   Specificity        ForAllTyFlag |--------------------------------------------------------------------------- | f :: forall a. type       HsForAllInvis       SpecifiedSpec      Specified | f :: forall {a}. type     HsForAllInvis       InferredSpec       Inferred@@ -1324,8 +1329,8 @@ |   This last form is nonsensical and is thus rejected. ---------------------------------------------------------------------------- -For more information regarding the interpretation of the resulting ArgFlag, see-Note [VarBndrs, TyCoVarBinders, TyConBinders, and visibility] in "GHC.Core.TyCo.Rep".+For more information regarding the interpretation of the resulting ForAllTyFlag, see+Note [VarBndrs, ForAllTyBinders, TyConBinders, and visibility] in "GHC.Core.TyCo.Rep". -}  ------------------------------------------@@ -1336,18 +1341,21 @@             -> TcM TcType tc_fun_type mode mult ty1 ty2 exp_kind = case mode_tyki mode of   TypeLevel ->-    do { arg_k <- newOpenTypeKind+    do { traceTc "tc_fun_type" (ppr ty1 $$ ppr ty2)+       ; arg_k <- newOpenTypeKind        ; res_k <- newOpenTypeKind-       ; ty1' <- tc_lhs_type mode ty1 arg_k-       ; ty2' <- tc_lhs_type mode ty2 res_k+       ; ty1'  <- tc_lhs_type mode ty1 arg_k+       ; ty2'  <- tc_lhs_type mode ty2 res_k        ; mult' <- tc_mult mode mult-       ; checkExpectedKind (HsFunTy noAnn mult ty1 ty2) (mkVisFunTy mult' ty1' ty2')+       ; checkExpectedKind (HsFunTy noAnn mult ty1 ty2)+                           (tcMkVisFunTy mult' ty1' ty2')                            liftedTypeKind exp_kind }   KindLevel ->  -- no representation polymorphism in kinds. yet.-    do { ty1' <- tc_lhs_type mode ty1 liftedTypeKind-       ; ty2' <- tc_lhs_type mode ty2 liftedTypeKind+    do { ty1'  <- tc_lhs_type mode ty1 liftedTypeKind+       ; ty2'  <- tc_lhs_type mode ty2 liftedTypeKind        ; mult' <- tc_mult mode mult-       ; checkExpectedKind (HsFunTy noAnn mult ty1 ty2) (mkVisFunTy mult' ty1' ty2')+       ; checkExpectedKind (HsFunTy noAnn mult ty1 ty2)+                           (tcMkVisFunTy mult' ty1' ty2')                            liftedTypeKind exp_kind }  {- Note [Skolem escape and forall-types]@@ -1392,10 +1400,10 @@ tupKindSort_maybe :: TcKind -> Maybe TupleSort tupKindSort_maybe k   | Just (k', _) <- splitCastTy_maybe k = tupKindSort_maybe k'-  | Just k'      <- tcView k            = tupKindSort_maybe k'-  | tcIsConstraintKind k = Just ConstraintTuple-  | tcIsLiftedTypeKind k   = Just BoxedTuple-  | otherwise            = Nothing+  | Just k'      <- coreView k          = tupKindSort_maybe k'+  | isConstraintKind k                  = Just ConstraintTuple+  | tcIsLiftedTypeKind k                = Just BoxedTuple+  | otherwise                           = Nothing  tc_tuple :: HsType GhcRn -> TcTyMode -> TupleSort -> [LHsType GhcRn] -> TcKind -> TcM TcType tc_tuple rn_ty mode tup_sort tys exp_kind@@ -1499,7 +1507,7 @@     is_app :: HsType GhcRn -> Bool     is_app (HsAppKindTy {})        = True     is_app (HsAppTy {})            = True-    is_app (HsOpTy _ _ _ (L _ op) _) = not (op `hasKey` funTyConKey)+    is_app (HsOpTy _ _ _ (L _ op) _) = not (op `hasKey` unrestrictedFunTyConKey)       -- I'm not sure why this funTyConKey test is necessary       -- Can it even happen?  Perhaps for   t1 `(->)` t2       -- but then maybe it's ok to treat that like a normal@@ -1565,12 +1573,12 @@     go_init n fun all_args       = go n fun empty_subst fun_ki all_args       where-        fun_ki = tcTypeKind fun-           -- We do (tcTypeKind fun) here, even though the caller+        fun_ki = typeKind fun+           -- We do (typeKind fun) here, even though the caller            -- knows the function kind, to absolutely guarantee            -- INVARIANT for 'go'            -- Note that in a typical application (F t1 t2 t3),-           -- the 'fun' is just a TyCon, so tcTypeKind is fast+           -- the 'fun' is just a TyCon, so typeKind is fast          empty_subst = mkEmptySubst $ mkInScopeSet $                       tyCoVarsOfType fun_ki@@ -1582,13 +1590,13 @@        -> [LHsTypeArg GhcRn]    -- Un-type-checked args        -> TcM (TcType, TcKind)  -- Result type and its kind     -- INVARIANT: in any call (go n fun subst fun_ki args)-    --               tcTypeKind fun  =  subst(fun_ki)+    --               typeKind fun  =  subst(fun_ki)     -- So the 'subst' and 'fun_ki' arguments are simply-    -- there to avoid repeatedly calling tcTypeKind.+    -- there to avoid repeatedly calling typeKind.     --     -- Reason for INVARIANT: to support the Purely Kinded Type Invariant     -- it's important that if fun_ki has a forall, then so does-    -- (tcTypeKind fun), because the next thing we are going to do+    -- (typeKind fun), because the next thing we are going to do     -- is apply 'fun' to an argument type.      -- Dispatch on all_args first, for performance reasons@@ -1605,16 +1613,16 @@         case ki_binder of          -- FunTy with PredTy on LHS, or ForAllTy with Inferred-        Named (Bndr _ Inferred) -> instantiate ki_binder inner_ki-        Anon InvisArg _         -> instantiate ki_binder inner_ki+        Named (Bndr _ Inferred)          -> instantiate ki_binder inner_ki+        Anon _ af | isInvisibleFunArg af -> instantiate ki_binder inner_ki          Named (Bndr _ Specified) ->  -- Visible kind application           do { traceTc "tcInferTyApps (vis kind app)"                        (vcat [ ppr ki_binder, ppr hs_ki_arg-                             , ppr (tyBinderType ki_binder)+                             , ppr (piTyBinderType ki_binder)                              , ppr subst ]) -             ; let exp_kind = substTy subst $ tyBinderType ki_binder+             ; let exp_kind = substTy subst $ piTyBinderType ki_binder              ; arg_mode <- mkHoleMode KindLevel HM_VTA                    -- HM_VKA: see Note [Wildcards in visible kind application]              ; ki_arg <- addErrCtxt (funAppCtxt orig_hs_ty hs_ki_arg n) $@@ -1636,8 +1644,8 @@       ---------------- HsValArg: a normal argument (fun ty)       (HsValArg arg : args, Just (ki_binder, inner_ki))         -- next binder is invisible; need to instantiate it-        | isInvisibleBinder ki_binder   -- FunTy with InvisArg on LHS;-                                        -- or ForAllTy with Inferred or Specified+        | isInvisiblePiTyBinder ki_binder   -- FunTy with constraint on LHS;+                                            -- or ForAllTy with Inferred or Specified          -> instantiate ki_binder inner_ki          -- "normal" case@@ -1645,9 +1653,9 @@          -> do { traceTc "tcInferTyApps (vis normal app)"                           (vcat [ ppr ki_binder                                 , ppr arg-                                , ppr (tyBinderType ki_binder)+                                , ppr (piTyBinderType ki_binder)                                 , ppr subst ])-                ; let exp_kind = substTy subst $ tyBinderType ki_binder+                ; let exp_kind = substTy subst $ piTyBinderType ki_binder                 ; arg' <- addErrCtxt (funAppCtxt orig_hs_ty arg n) $                           tc_lhs_type mode arg exp_kind                 ; traceTc "tcInferTyApps (vis normal app) 2" (ppr exp_kind)@@ -1660,7 +1668,7 @@            do { let arrows_needed = n_initial_val_args all_args               ; co <- matchExpectedFunKind (HsTypeRnThing $ unLoc hs_ty) arrows_needed substed_fun_ki -              ; fun' <- zonkTcType (fun `mkTcCastTy` co)+              ; fun' <- zonkTcType (fun `mkCastTy` co)                      -- This zonk is essential, to expose the fruits                      -- of matchExpectedFunKind to the 'go' loop @@ -1668,7 +1676,7 @@                    vcat [ ppr fun <+> dcolon <+> ppr fun_ki                         , ppr arrows_needed                         , ppr co-                        , ppr fun' <+> dcolon <+> ppr (tcTypeKind fun')]+                        , ppr fun' <+> dcolon <+> ppr (typeKind fun')]               ; go_init n fun' all_args }                 -- Use go_init to establish go's INVARIANT       where@@ -1701,14 +1709,14 @@       = failWith $ TcRnInvalidVisibleKindArgument arg ty  mkAppTyM :: Subst-         -> TcType -> TyCoBinder    -- fun, plus its top-level binder+         -> TcType -> PiTyBinder    -- fun, plus its top-level binder          -> TcType                  -- arg          -> TcM (Subst, TcType)  -- Extended subst, plus (fun arg) -- Precondition: the application (fun arg) is well-kinded after zonking --               That is, the application makes sense -- -- Precondition: for (mkAppTyM subst fun bndr arg)---       tcTypeKind fun  =  Pi bndr. body+--       typeKind fun  =  Pi bndr. body --  That is, fun always has a ForAllTy or FunTy at the top --           and 'bndr' is fun's pi-binder --@@ -1716,7 +1724,7 @@ --                invariant, then so does the result type (fun arg) -- -- We do not require that---    tcTypeKind arg = tyVarKind (binderVar bndr)+--    typeKind arg = tyVarKind (binderVar bndr) -- This must be true after zonking (precondition 1), but it's not -- required for the (PKTI). mkAppTyM subst fun ki_binder arg@@ -1751,7 +1759,7 @@               (ppr fun <+> dcolon <+> ppr fun_kind $$ ppr arg) $     mkAppTy fun arg   where-    fun_kind = tcTypeKind fun+    fun_kind = typeKind fun  isTrickyTvBinder :: TcTyVar -> Bool -- NB: isTrickyTvBinder is just an optimisation@@ -1762,14 +1770,14 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ During type inference, we maintain this invariant - (PKTI) It is legal to call 'tcTypeKind' on any Type ty,+ (PKTI) It is legal to call 'typeKind' on any Type ty,         on any sub-term of ty, /without/ zonking ty          Moreover, any such returned kind         will itself satisfy (PKTI) -By "legal to call tcTypeKind" we mean "tcTypeKind will not crash".-The way in which tcTypeKind can crash is in applications+By "legal to call typeKind" we mean "typeKind will not crash".+The way in which typeKind can crash is in applications     (a t1 t2 .. tn) if 'a' is a type variable whose kind doesn't have enough arrows or foralls.  (The crash is in piResultTys.)@@ -1782,7 +1790,7 @@     a :: kappa then consider the type     (a Int)-If we call tcTypeKind on that, we'll crash, because the (un-zonked)+If we call typeKind on that, we'll crash, because the (un-zonked) kind of 'a' is just kappa, not an arrow kind.  So we must zonk first.  So the type inference engine is very careful when building applications.@@ -1841,7 +1849,7 @@  saturateFamApp :: TcType -> TcKind -> TcM (TcType, TcKind) -- Precondition for (saturateFamApp ty kind):---     tcTypeKind ty = kind+--     typeKind ty = kind -- -- If 'ty' is an unsaturated family application with trailing -- invisible arguments, instantiate them.@@ -1849,10 +1857,10 @@  saturateFamApp ty kind   | Just (tc, args) <- tcSplitTyConApp_maybe ty-  , mustBeSaturated tc+  , tyConMustBeSaturated tc   , let n_to_inst = tyConArity tc - length args   = do { (extra_args, ki') <- tcInstInvisibleTyBindersN n_to_inst kind-       ; return (ty `mkTcAppTys` extra_args, ki') }+       ; return (ty `mkAppTys` extra_args, ki') }   | otherwise   = return (ty, kind) @@ -1920,7 +1928,7 @@               , text "act_kind':" <+> ppr act_kind'               , text "exp_kind:" <+> ppr exp_kind ] -       ; let res_ty = ty `mkTcAppTys` new_args+       ; let res_ty = ty `mkAppTys` new_args         ; if act_kind' `tcEqType` exp_kind          then return res_ty  -- This is very common@@ -1928,7 +1936,7 @@                  ; traceTc "checkExpectedKind" (vcat [ ppr act_kind                                                      , ppr exp_kind                                                      , ppr co_k ])-                ; return (res_ty `mkTcCastTy` co_k) } }+                ; return (res_ty `mkCastTy` co_k) } }     where       -- We need to make sure that both kinds have the same number of implicit       -- foralls out front. If the actual kind has more, instantiate accordingly.@@ -2465,7 +2473,7 @@                -- recursive group.                -- See Note [Inferring kinds for type declarations] in GHC.Tc.TyCl -             tc_binders = mkAnonTyConBinders VisArg tc_tvs+             tc_binders = mkAnonTyConBinders tc_tvs                -- Also, note that tc_binders has the tyvars from only the                -- user-written tyvarbinders. See S1 in Note [How TcTyCons work]                -- in GHC.Tc.TyCl@@ -3029,7 +3037,7 @@                                       , sm_tvtv = SMDSkolemTv skol_info }           ; (req_tv_bndrs, thing) <- tcExplicitTKBndrsX skol_mode bndrs thing_inside             -- req_tv_bndrs :: [VarBndr TyVar ()],-            -- but we want [VarBndr TyVar ArgFlag]+            -- but we want [VarBndr TyVar ForAllTyFlag]           ; return (tyVarReqToBinders req_tv_bndrs, thing) }    HsForAllInvis { hsf_invis_bndrs = bndrs }@@ -3038,7 +3046,7 @@                                       , sm_tvtv = SMDSkolemTv skol_info }           ; (inv_tv_bndrs, thing) <- tcExplicitTKBndrsX skol_mode bndrs thing_inside             -- inv_tv_bndrs :: [VarBndr TyVar Specificity],-            -- but we want [VarBndr TyVar ArgFlag]+            -- but we want [VarBndr TyVar ForAllTyFlag]           ; return (tyVarSpecToBinders inv_tv_bndrs, thing) }  --------------------------------------@@ -3693,12 +3701,10 @@         ; uniqs   <- newUniqueSupply         ; rdr_env <- getLocalRdrEnv         ; lvl     <- getTcLevel-        ; let new_occs = [ occ-                         | str <- allNameStrings-                         , let occ = mkOccName tvName str-                         , isNothing (lookupLocalRdrOcc rdr_env occ)-                         -- Note [Avoid name clashes for associated data types]-                         , not (occ `elem` avoid_occs) ]+        ; let new_occs = Inf.filter (\ occ ->+                  isNothing (lookupLocalRdrOcc rdr_env occ) &&+                  -- Note [Avoid name clashes for associated data types]+                  not (occ `elem` avoid_occs)) $ mkOccName tvName <$> allNameStrings               new_uniqs = uniqsFromSupply uniqs               subst = mkEmptySubst in_scope               details = SkolemTv skol_info (pushTcLevel lvl) False@@ -3708,7 +3714,7 @@                 = case splitPiTy_maybe kind of                     Nothing -> (reverse acc, substTy subst kind) -                    Just (Anon af arg, kind')+                    Just (Anon arg af, kind')                       -> go occs' uniqs' subst' (tcb : acc) kind'                       where                         tcb    = Bndr tv (AnonTCB af)@@ -3716,8 +3722,8 @@                         name   = mkInternalName uniq occ loc                         tv     = mkTcTyVar name arg' details                         subst' = extendSubstInScope subst tv-                        (uniq:uniqs') = uniqs-                        (occ:occs')   = occs+                        uniq:uniqs' = uniqs+                        Inf occ occs' = occs                      Just (Named (Bndr tv vis), kind')                       -> go occs uniqs subst' (tcb : acc) kind'@@ -3729,8 +3735,8 @@         ; return (go new_occs new_uniqs subst [] kind) }  isAllowedDataResKind :: AllowedDataResKind -> Kind -> Bool-isAllowedDataResKind AnyTYPEKind  kind = tcIsRuntimeTypeKind kind-isAllowedDataResKind AnyBoxedKind kind = tcIsBoxedTypeKind kind+isAllowedDataResKind AnyTYPEKind  kind = isTypeLikeKind     kind+isAllowedDataResKind AnyBoxedKind kind = tcIsBoxedTypeKind  kind isAllowedDataResKind LiftedKind   kind = tcIsLiftedTypeKind kind  -- | Checks that the return kind in a data declaration's kind signature is@@ -3813,7 +3819,7 @@     -- In the particular case of a data family, permit a return kind of the     -- form `:: k` (where `k` is a bare kind variable).     is_kind_var :: Bool-    is_kind_var | is_data_family = isJust (tcGetCastedTyVar_maybe res_kind)+    is_kind_var | is_data_family = isJust (getCastedTyVar_maybe res_kind)                 | otherwise      = False      err_msg :: DynFlags -> TcRnMessage@@ -3821,7 +3827,7 @@       TcRnInvalidReturnKind data_sort (allowed_kind dflags) kind (ext_hint dflags)      ext_hint dflags-      | tcIsRuntimeTypeKind kind+      | isTypeLikeKind kind       , is_newtype       , not (xopt LangExt.UnliftedNewtypes dflags)       = Just SuggestUnliftedNewtypes@@ -3835,7 +3841,7 @@ -- | Checks that the result kind of a class is exactly `Constraint`, rejecting -- type synonyms and type families that reduce to `Constraint`. See #16826. checkClassKindSig :: Kind -> TcM ()-checkClassKindSig kind = checkTc (tcIsConstraintKind kind) err_msg+checkClassKindSig kind = checkTc (isConstraintKind kind) err_msg   where     err_msg :: TcRnMessage     err_msg = TcRnClassKindNotConstraint kind@@ -3852,7 +3858,7 @@     go fun_kind subst all_args@(arg : args)       | Just (tcb, inner_kind) <- splitPiTy_maybe fun_kind       = case tcb of-          Anon af _           -> AnonTCB af   : go inner_kind subst  args+          Anon _ af           -> AnonTCB af   : go inner_kind subst  args           Named (Bndr tv vis) -> NamedTCB vis : go inner_kind subst' args                  where                     subst' = extendTCvSubst subst tv arg@@ -3958,7 +3964,9 @@                     (theta, wcx) <- tcPartialContext mode hs_ctxt                    ; ek <- newOpenTypeKind-                  ; tau <- addTypeCtxt hs_tau $+                  ; tau <- -- Don't do (addTypeCtxt hs_tau) here else we get+                           --   In the type <blah>+                           --   In the type signature: foo :: <blah>                            tc_lhs_type mode hs_tau ek                    ; return (wcs, wcx, theta, tau) }@@ -3970,7 +3978,7 @@           -- No kind-generalization here:        ; kindGeneralizeNone (mkInvisForAllTys outer_tv_bndrs $-                             mkPhiTy theta $+                             tcMkPhiTy theta $                              tau)         -- Spit out the wildcards (including the extra-constraints one)@@ -4138,9 +4146,6 @@  * Because it is ill-kinded (unifying something of kind Constraint with   something of kind Type), it should trip an assert in writeMetaTyVarRef.-  However, writeMetaTyVarRef uses eqType, not tcEqType, to avoid falling-  over in this scenario (and another scenario, as detailed in-  Note [coreView vs tcView] in GHC.Core.Type).  Result works fine, but it may eventually bite us. 
compiler/GHC/Tc/Gen/Match.hs view
@@ -113,7 +113,7 @@         ; matchExpectedFunTys herald ctxt arity exp_ty $ \ pat_tys rhs_ty ->              -- NB: exp_type may be polymorphic, but              --     matchExpectedFunTys can cope with that-          tcScalingUsage Many $+          tcScalingUsage ManyTy $           -- toplevel bindings and let bindings are, at the           -- moment, always unrestricted. The value being bound           -- must, accordingly, be unrestricted. Hence them@@ -178,7 +178,7 @@            -> TcM (GRHSs GhcTc (LHsExpr GhcTc)) -- Used for pattern bindings tcGRHSsPat grhss res_ty-  = tcScalingUsage Many $+  = tcScalingUsage ManyTy $       -- Like in tcMatchesFun, this scaling happens because all       -- let bindings are unrestricted. A difference, here, is       -- that when this is not the case, any more, we will have to@@ -421,7 +421,7 @@  tcGuardStmt :: TcExprStmtChecker tcGuardStmt _ (BodyStmt _ guard _ _) res_ty thing_inside-  = do  { guard' <- tcScalingUsage Many $ tcCheckMonoExpr guard boolTy+  = do  { guard' <- tcScalingUsage ManyTy $ tcCheckMonoExpr guard boolTy           -- Scale the guard to Many (see #19120 and #19193)         ; thing  <- thing_inside res_ty         ; return (BodyStmt boolTy guard' noSyntaxExpr noSyntaxExpr, thing) }@@ -434,7 +434,7 @@           -- The multiplicity of x in u must be the same as the multiplicity at           -- which the rhs has been consumed. When solving #18738, we want these           -- two multiplicity to still be the same.-          (rhs', rhs_ty) <- tcScalingUsage Many $ tcInferRhoNC rhs+          (rhs', rhs_ty) <- tcScalingUsage ManyTy $ tcInferRhoNC rhs                                    -- Stmt has a context already         ; hasFixedRuntimeRep_syntactic FRRBindStmtGuard rhs_ty         ; (pat', thing)  <- tcCheckPat_O (StmtCtxt ctxt) (lexprCtOrigin rhs)@@ -542,7 +542,7 @@              -- typically something like [(Int,Bool,Int)]              -- We don't know what tuple_ty is yet, so we use a variable        ; let mk_n_bndr :: Name -> TcId -> TcId-             mk_n_bndr n_bndr_name bndr_id = mkLocalId n_bndr_name Many (n_app (idType bndr_id))+             mk_n_bndr n_bndr_name bndr_id = mkLocalId n_bndr_name ManyTy (n_app (idType bndr_id))               -- Ensure that every old binder of type `b` is linked up with its              -- new binder which should have type `n b`@@ -735,7 +735,7 @@         --------------- Building the bindersMap ----------------        ; let mk_n_bndr :: Name -> TcId -> TcId-             mk_n_bndr n_bndr_name bndr_id = mkLocalId n_bndr_name Many (n_app (idType bndr_id))+             mk_n_bndr n_bndr_name bndr_id = mkLocalId n_bndr_name ManyTy (n_app (idType bndr_id))               -- Ensure that every old binder of type `b` is linked up with its              -- new binder which should have type `n b`@@ -916,7 +916,7 @@          res_ty thing_inside   = do  { let tup_names = rec_names ++ filterOut (`elem` rec_names) later_names         ; tup_elt_tys <- newFlexiTyVarTys (length tup_names) liftedTypeKind-        ; let tup_ids = zipWith (\n t -> mkLocalId n Many t) tup_names tup_elt_tys+        ; let tup_ids = zipWith (\n t -> mkLocalId n ManyTy t) tup_names tup_elt_tys                 -- Many because it's a recursive definition               tup_ty  = mkBigCoreTupTy tup_elt_tys 
compiler/GHC/Tc/Gen/Pat.hs view
@@ -54,6 +54,7 @@ import GHC.Tc.Types.Origin import GHC.Core.TyCon import GHC.Core.Type+import GHC.Core.Coercion import GHC.Core.DataCon import GHC.Core.PatSyn import GHC.Core.ConLike@@ -232,7 +233,7 @@                                 -- level, we'd be in checking mode (see tcConArg)                                 -- hence this assertion                                 do { bndr_ty <- inferResultToType infer_res-                                   ; return (mkTcNomReflCo bndr_ty, bndr_ty) }+                                   ; return (mkNomReflCo bndr_ty, bndr_ty) }        ; let bndr_mult = scaledMult exp_pat_ty        ; bndr_id <- newLetBndr no_gen bndr_name bndr_mult bndr_ty        ; traceTc "tcPatBndr(nosig)" (vcat [ ppr bind_lvl@@ -353,7 +354,7 @@ -------------------- -- See Note [Wrapper returned from tcSubMult] in GHC.Tc.Utils.Unify. checkManyPattern :: Scaled a -> TcM HsWrapper-checkManyPattern pat_ty = tcSubMult NonLinearPatternOrigin Many (scaledMult pat_ty)+checkManyPattern pat_ty = tcSubMult NonLinearPatternOrigin ManyTy (scaledMult pat_ty)  tc_pat  :: Scaled ExpSigmaTypeFRR         -- ^ Fully refined result type@@ -392,7 +393,7 @@          -- Check that the expected pattern type is itself lifted         ; pat_ty <- readExpType (scaledThing pat_ty)-        ; _ <- unifyType Nothing (tcTypeKind pat_ty) liftedTypeKind+        ; _ <- unifyType Nothing (typeKind pat_ty) liftedTypeKind          ; return (mkHsWrapPat mult_wrap (LazyPat x pat') pat_ty, res) } @@ -1106,7 +1107,7 @@        ; (wrap, pat_rho) <- topInstantiate orig pat_ty        ; (co, res) <- inner_match pat_rho        ; traceTc "matchExpectedPatTy" (ppr pat_ty $$ ppr wrap)-       ; return (mkWpCastN (mkTcSymCo co) <.> wrap, res) }+       ; return (mkWpCastN (mkSymCo co) <.> wrap, res) }  ---------------------------- matchExpectedConTy :: PatEnv@@ -1143,10 +1144,10 @@              -- for actual vs. expected in error messages.         ; let tys' = mkTyVarTys tvs'-             co2 = mkTcUnbranchedAxInstCo co_tc tys' []+             co2 = mkUnbranchedAxInstCo Representational co_tc tys' []              -- co2 : T (ty1,ty2) ~R T7 ty1 ty2 -             full_co = mkTcSubCo (mkTcSymCo co1) `mkTcTransCo` co2+             full_co = mkSubCo (mkSymCo co1) `mkTransCo` co2              -- full_co :: pat_rho ~R T7 ty1 ty2         ; return ( mkWpCastR full_co <.> wrap, tys') }@@ -1155,7 +1156,7 @@   = do { pat_ty <- expTypeToType (scaledThing exp_pat_ty)        ; (wrap, pat_rho) <- topInstantiate orig pat_ty        ; (coi, tys) <- matchExpectedTyConApp data_tc pat_rho-       ; return (mkWpCastN (mkTcSymCo coi) <.> wrap, tys) }+       ; return (mkWpCastN (mkSymCo coi) <.> wrap, tys) }  {- Note [Matching constructor patterns]@@ -1247,7 +1248,7 @@                   (arityErr (text "constructor") con_like con_arity no_of_args)                -- forgetting to filter out inferred binders led to #20443-        ; let con_spec_binders = filter ((== SpecifiedSpec) . binderArgFlag) $+        ; let con_spec_binders = filter ((== SpecifiedSpec) . binderFlag) $                                  conLikeUserTyVarBinders con_like         ; checkTc (type_args `leLength` con_spec_binders)                   (TcRnTooManyTyArgsInConPattern con_like (length con_spec_binders) (length type_args))
compiler/GHC/Tc/Gen/Rule.hs view
@@ -17,7 +17,6 @@ import GHC.Tc.Solver import GHC.Tc.Solver.Monad ( runTcS ) import GHC.Tc.Types.Constraint-import GHC.Core.Predicate import GHC.Tc.Types.Origin import GHC.Tc.Utils.TcMType import GHC.Tc.Utils.TcType@@ -25,9 +24,12 @@ import GHC.Tc.Gen.Expr import GHC.Tc.Utils.Env import GHC.Tc.Utils.Unify( buildImplicationFor )-import GHC.Tc.Types.Evidence( mkTcCoVarCo )+ import GHC.Core.Type+import GHC.Core.Coercion( mkCoVarCo ) import GHC.Core.TyCon( isTypeFamilyTyCon )+import GHC.Core.Predicate+ import GHC.Types.Id import GHC.Types.Var( EvVar, tyVarName ) import GHC.Types.Var.Set@@ -165,7 +167,8 @@                                 , text "rule_ty:" <+> ppr rule_ty                                 , text "ty_bndrs:" <+> ppr ty_bndrs                                 , text "qtkvs ++ tpl_ids:" <+> ppr (qtkvs ++ tpl_ids)-                                , vcat [ ppr id <+> dcolon <+> ppr (idType id) | id <- tpl_ids ]+                                , text "tpl_id info:" <+>+                                  vcat [ ppr id <+> dcolon <+> ppr (idType id) | id <- tpl_ids ]                   ])         -- SimplfyRule Plan, step 5@@ -229,7 +232,7 @@ tcRuleTmBndrs rule_name (L _ (RuleBndr _ (L _ name)) : rule_bndrs)   = do  { ty <- newOpenFlexiTyVarTy         ; (tyvars, tmvars) <- tcRuleTmBndrs rule_name rule_bndrs-        ; return (tyvars, mkLocalId name Many ty : tmvars) }+        ; return (tyvars, mkLocalId name ManyTy ty : tmvars) } tcRuleTmBndrs rule_name (L _ (RuleBndrSig _ (L _ name) rn_ty) : rule_bndrs) --  e.g         x :: a->a --  The tyvar 'a' is brought into scope first, just as if you'd written@@ -238,7 +241,7 @@ --   error for each out-of-scope type variable used   = do  { let ctxt = RuleSigCtxt rule_name name         ; (_ , tvs, id_ty) <- tcHsPatSigType ctxt HM_Sig rn_ty OpenKind-        ; let id  = mkLocalId name Many id_ty+        ; let id  = mkLocalId name ManyTy id_ty                     -- See Note [Typechecking pattern signature binders] in GHC.Tc.Gen.HsType                -- The type variables scope over subsequent bindings; yuk@@ -444,7 +447,7 @@           EvVarDest ev_id -> return ev_id           HoleDest hole   -> -- See Note [Quantifying over coercion holes]                              do { ev_id <- newEvVar pred-                                ; fillCoercionHole hole (mkTcCoVarCo ev_id)+                                ; fillCoercionHole hole (mkCoVarCo ev_id)                                 ; return ev_id }     mk_quant_ev ct = pprPanic "mk_quant_ev" (ppr ct) 
compiler/GHC/Tc/Gen/Sig.hs view
@@ -26,6 +26,7 @@    ) where  import GHC.Prelude+import GHC.Data.FastString  import GHC.Driver.Session import GHC.Driver.Backend@@ -51,9 +52,10 @@ import GHC.Core( hasSomeUnfolding ) import GHC.Core.Type ( mkTyVarBinders ) import GHC.Core.Multiplicity+import GHC.Core.TyCo.Rep( mkNakedFunTy )  import GHC.Types.Error-import GHC.Types.Var ( TyVar, Specificity(..), tyVarKind, binderVars )+import GHC.Types.Var ( TyVar, Specificity(..), tyVarKind, binderVars, invisArgTypeLike ) import GHC.Types.Id  ( Id, idName, idType, setInlinePragma                      , mkLocalId, realIdUnfolding ) import GHC.Types.Basic@@ -229,7 +231,7 @@   = do { sigma_ty <- tcHsSigWcType ctxt_no_rrc hs_sig_ty        ; traceTc "tcuser" (ppr sigma_ty)        ; return $-         CompleteSig { sig_bndr  = mkLocalId name Many sigma_ty+         CompleteSig { sig_bndr  = mkLocalId name ManyTy sigma_ty                                    -- We use `Many' as the multiplicity here,                                    -- as if this identifier corresponds to                                    -- anything, it is a top-level@@ -246,7 +248,7 @@   where     name   = case mb_name of                Just n  -> n-               Nothing -> mkUnboundName (mkVarOcc "<expression>")+               Nothing -> mkUnboundName (mkVarOccFS (fsLit "<expression>"))      ctxt_rrc    = ctxt_fn (lhsSigWcTypeContextSpan hs_sig_ty)     ctxt_no_rrc = ctxt_fn NoRRC@@ -316,7 +318,7 @@                                         && go ty       HsQualTy { hst_ctxt = ctxt                , hst_body = ty }  -> gos (unLoc ctxt) && go ty-      HsSpliceTy (HsUntypedSpliceTop _ ty) _ -> go $ L noSrcSpanA ty+      HsSpliceTy (HsUntypedSpliceTop _ ty) _ -> go ty       HsSpliceTy (HsUntypedSpliceNested _) _ -> True       HsTyLit{} -> True       HsTyVar{} -> True@@ -484,10 +486,18 @@     build_patsyn_type implicit_bndrs univ_bndrs req ex_bndrs prov body       = mkInvisForAllTys implicit_bndrs $         mkInvisForAllTys univ_bndrs $-        mkPhiTy req $+        mk_naked_phi_ty req $         mkInvisForAllTys ex_bndrs $-        mkPhiTy prov $+        mk_naked_phi_ty prov $         body++    -- Use mk_naked_phi_ty because we call build_patsyn_type /before zonking/+    -- just before kindGeneraliseAll, and the invariants that mkPhiTy checks+    -- don't hold of the un-zonked types.  #22521 was a case in point.+    -- (We also called build_patsyn_type on the fully zonked type, so mkPhiTy+    --  would work; but it doesn't seem worth duplicating the code.)+    mk_naked_phi_ty :: [TcPredType] -> TcType -> TcType+    mk_naked_phi_ty theta body = foldr (mkNakedFunTy invisArgTypeLike) body theta  ppr_tvs :: [TyVar] -> SDoc ppr_tvs tvs = braces (vcat [ ppr tv <+> dcolon <+> ppr (tyVarKind tv)
compiler/GHC/Tc/Gen/Splice.hs view
@@ -118,7 +118,6 @@ import GHC.Unit.Module.Deps  import GHC.Utils.Misc-import GHC.Utils.Trace import GHC.Utils.Panic as Panic import GHC.Utils.Panic.Plain import GHC.Utils.Lexeme@@ -677,7 +676,7 @@        --   (See Note [The life cycle of a TH quotation] in GHC.Hs.Expr)        -- We'll typecheck it again when we splice it in somewhere        ; (tc_expr, expr_ty) <- setStage (Brack cur_stage (TcPending ps_ref lie_var wrapper)) $-                                tcScalingUsage Many $+                                tcScalingUsage ManyTy $                                 -- Scale by Many, TH lifting is currently nonlinear (#18465)                                 tcInferRhoNC expr                                 -- NC for no context; tcBracket does that@@ -780,7 +779,7 @@   = do { meta_ty <- tcMetaTy meta_ty_name          -- Expected type of splice, e.g. m Exp        ; let expected_type = mkAppTy m_var meta_ty-       ; expr' <- tcScalingUsage Many $ tcCheckPolyExpr expr expected_type+       ; expr' <- tcScalingUsage ManyTy $ tcCheckPolyExpr expr expected_type                   -- Scale by Many, TH lifting is currently nonlinear (#18465)        ; return (PendingTcSplice splice_name expr') }   where@@ -1904,7 +1903,7 @@                 -- In particular, the type might have kind                 -- variables inside it (#7477) -        ; traceTc "reifyInstances'" (ppr ty $$ ppr (tcTypeKind ty))+        ; traceTc "reifyInstances'" (ppr ty $$ ppr (typeKind ty))         ; case splitTyConApp_maybe ty of   -- This expands any type synonyms             Just (tc, tys)                 -- See #7910                | Just cls <- tyConClass_maybe tc@@ -2110,8 +2109,10 @@   | Just cls <- tyConClass_maybe tc   = reifyClass cls -  | isFunTyCon tc-  = return (TH.PrimTyConI (reifyName tc) 2                False)+{-  Seems to be just a short cut for the next equation -- omit+  | tc `hasKey` fUNTyConKey -- I'm not quite sure what is happening here+  = return (TH.PrimTyConI (reifyName tc) 2 False)+-}    | isPrimTyCon tc   = return (TH.PrimTyConI (reifyName tc) (length (tyConVisibleTyVars tc))@@ -2255,7 +2256,7 @@      subst_tv_binders subst tv_bndrs =       let tvs            = binderVars tv_bndrs-          flags          = map binderArgFlag tv_bndrs+          flags          = binderFlags tv_bndrs           (subst', tvs') = substTyVarBndrs subst tvs           tv_bndrs'      = map (\(tv,fl) -> Bndr tv fl) (zip tvs' flags)       in (subst', tv_bndrs')@@ -2349,7 +2350,7 @@ annotThType _    _  th_ty@(TH.SigT {}) = return th_ty annotThType True ty th_ty   | not $ isEmptyVarSet $ filterVarSet isTyVar $ tyCoVarsOfType ty-  = do { let ki = tcTypeKind ty+  = do { let ki = typeKind ty        ; th_ki <- reifyKind ki        ; return (TH.SigT th_ty th_ki) } annotThType _    _ th_ty = return th_ty@@ -2363,7 +2364,7 @@      map (is_poly_ty . tyVarKind)      tc_vis_tvs      -- See "Wrinkle: Oversaturated data family instances" in      -- @Note [Reified instances and explicit kind signatures]@-  ++ map (is_poly_ty . tyCoBinderType) tc_res_kind_vis_bndrs -- (1) in Wrinkle+  ++ map (is_poly_ty . piTyBinderType) tc_res_kind_vis_bndrs -- (1) in Wrinkle   ++ repeat True                                             -- (2) in Wrinkle   where     is_poly_ty :: Type -> Bool@@ -2375,8 +2376,8 @@     tc_vis_tvs :: [TyVar]     tc_vis_tvs = tyConVisibleTyVars tc -    tc_res_kind_vis_bndrs :: [TyCoBinder]-    tc_res_kind_vis_bndrs = filter isVisibleBinder $ fst $ splitPiTys $ tyConResKind tc+    tc_res_kind_vis_bndrs :: [PiTyBinder]+    tc_res_kind_vis_bndrs = filter isVisiblePiTyBinder $ fst $ splitPiTys $ tyConResKind tc  {- Note [Reified instances and explicit kind signatures]@@ -2531,7 +2532,7 @@                -- Note [Reified instances and explicit kind signatures]                if (null cons || isGadtSyntaxTyCon rep_tc)                      && tyConAppNeedsKindSig False fam_tc (length ee_lhs)-               then do { let full_kind = tcTypeKind (mkTyConApp fam_tc ee_lhs)+               then do { let full_kind = typeKind (mkTyConApp fam_tc ee_lhs)                        ; th_full_kind <- reifyKind full_kind                        ; pure $ Just th_full_kind }                else pure Nothing@@ -2567,23 +2568,23 @@     -- `Type` argument is invisible (#15792).     filter_out_invisible_args :: Type -> [Type] -> [Type]     filter_out_invisible_args ty_head ty_args =-      filterByList (map isVisibleArgFlag $ appTyArgFlags ty_head ty_args)+      filterByList (map isVisibleForAllTyFlag $ appTyForAllTyFlags ty_head ty_args)                    ty_args-reifyType ty@(FunTy { ft_af = af, ft_mult = Many, ft_arg = t1, ft_res = t2 })-  | InvisArg <- af = reify_for_all Inferred ty  -- Types like ((?x::Int) => Char -> Char)-  | otherwise      = do { [r1,r2] <- reifyTypes [t1,t2]-                        ; return (TH.ArrowT `TH.AppT` r1 `TH.AppT` r2) }+reifyType ty@(FunTy { ft_af = af, ft_mult = ManyTy, ft_arg = t1, ft_res = t2 })+  | isInvisibleFunArg af = reify_for_all Inferred ty  -- Types like ((?x::Int) => Char -> Char)+  | otherwise            = do { [r1,r2] <- reifyTypes [t1,t2]+                              ; return (TH.ArrowT `TH.AppT` r1 `TH.AppT` r2) } reifyType ty@(FunTy { ft_af = af, ft_mult = tm, ft_arg = t1, ft_res = t2 })-  | InvisArg <- af = noTH LinearInvisibleArgument ty-  | otherwise      = do { [rm,r1,r2] <- reifyTypes [tm,t1,t2]-                        ; return (TH.MulArrowT `TH.AppT` rm `TH.AppT` r1 `TH.AppT` r2) }+  | isInvisibleFunArg af = noTH LinearInvisibleArgument ty+  | otherwise            = do { [rm,r1,r2] <- reifyTypes [tm,t1,t2]+                              ; return (TH.MulArrowT `TH.AppT` rm `TH.AppT` r1 `TH.AppT` r2) } reifyType (CastTy t _)      = reifyType t -- Casts are ignored in TH reifyType ty@(CoercionTy {})= noTH CoercionsInTypes ty -reify_for_all :: TyCoRep.ArgFlag -> TyCoRep.Type -> TcM TH.Type+reify_for_all :: TyCoRep.ForAllTyFlag -> TyCoRep.Type -> TcM TH.Type -- Arg of reify_for_all is always ForAllTy or a predicate FunTy reify_for_all argf ty-  | isVisibleArgFlag argf+  | isVisibleForAllTyFlag argf   = do let (req_bndrs, phi) = tcSplitForAllReqTVBinders ty        tvbndrs' <- reifyTyVarBndrs req_bndrs        phi' <- reifyType phi@@ -2614,7 +2615,7 @@        ; req'        <- reifyCxt req        ; exTyVars'   <- reifyTyVarBndrs exTyVars        ; prov'       <- reifyCxt prov-       ; tau'        <- reifyType (mkVisFunTys argTys resTy)+       ; tau'        <- reifyType (mkScaledFunTys argTys resTy)        ; return $ TH.ForallT univTyVars' req'                 $ TH.ForallT exTyVars' prov' tau' } @@ -2691,7 +2692,7 @@                 -- don't count specified binders as contributing towards                 -- injective positions in the kind of the tycon.           tc (length tys)-      = do { let full_kind = tcTypeKind (mkTyConApp tc tys)+      = do { let full_kind = typeKind (mkTyConApp tc tys)            ; th_full_kind <- reifyKind full_kind            ; return (TH.SigT th_type th_full_kind) }       | otherwise
compiler/GHC/Tc/Instance/Class.hs view
@@ -38,6 +38,7 @@ import GHC.Types.Var  import GHC.Core.Predicate+import GHC.Core.Coercion import GHC.Core.InstEnv import GHC.Core.Type import GHC.Core.Make ( mkCharExpr, mkNaturalExpr, mkStringExprFS, mkCoreLams )@@ -54,8 +55,6 @@  import Language.Haskell.Syntax.Basic (FieldLabelString(..)) -import Data.Maybe- {- ******************************************************************* *                                                                    *               A helper for associated types within@@ -154,20 +153,17 @@                              -- See Note [Shortcut solving: overlap]                 -> Class -> [Type] -> TcM ClsInstResult matchGlobalInst dflags short_cut clas tys-  | cls_name == knownNatClassName-  = matchKnownNat    dflags short_cut clas tys-  | cls_name == knownSymbolClassName-  = matchKnownSymbol dflags short_cut clas tys-  | cls_name == knownCharClassName-  = matchKnownChar dflags short_cut clas tys-  | isCTupleClass clas                = matchCTuple          clas tys-  | cls_name == typeableClassName     = matchTypeable        clas tys-  | cls_name == withDictClassName     = matchWithDict             tys-  | clas `hasKey` heqTyConKey         = matchHeteroEquality       tys-  | clas `hasKey` eqTyConKey          = matchHomoEquality         tys-  | clas `hasKey` coercibleTyConKey   = matchCoercible            tys-  | cls_name == hasFieldClassName     = matchHasField dflags short_cut clas tys-  | otherwise                         = matchInstEnv dflags short_cut clas tys+  | cls_name == knownNatClassName     = matchKnownNat    dflags short_cut clas tys+  | cls_name == knownSymbolClassName  = matchKnownSymbol dflags short_cut clas tys+  | cls_name == knownCharClassName    = matchKnownChar   dflags short_cut clas tys+  | isCTupleClass clas                = matchCTuple                       clas tys+  | cls_name == typeableClassName     = matchTypeable                     clas tys+  | cls_name == withDictClassName     = matchWithDict                          tys+  | clas `hasKey` heqTyConKey         = matchHeteroEquality                    tys+  | clas `hasKey` eqTyConKey          = matchHomoEquality                      tys+  | clas `hasKey` coercibleTyConKey   = matchCoercible                         tys+  | cls_name == hasFieldClassName     = matchHasField    dflags short_cut clas tys+  | otherwise                         = matchInstEnv     dflags short_cut clas tys   where     cls_name = className clas @@ -193,7 +189,7 @@              -- Nothing matches             ([], NoUnifiers, _)-                -> do { traceTc "matchClass not matching" (ppr pred)+                -> do { traceTc "matchClass not matching" (ppr pred $$ ppr (ie_local instEnvs))                       ; return NoInstance }              -- A single match (& no safe haskell failure)@@ -427,7 +423,7 @@                     -- then tcRep is SNat     , Just (_, co_rep) <- tcInstNewTyCon_maybe tcRep [ty]           -- SNat n ~ Integer-    , let ev_tm = mkEvCast et (mkTcSymCo (mkTcTransCo co_dict co_rep))+    , let ev_tm = mkEvCast et (mkSymCo (mkTransCo co_dict co_rep))     = return $ OneInst { cir_new_theta = []                        , cir_mk_ev     = \_ -> ev_tm                        , cir_what      = BuiltinInstance }@@ -454,8 +450,8 @@     -- and in that case let     -- co :: C t1 ..tn ~R# inst_meth_ty   , Just (inst_meth_ty, co) <- tcInstNewTyCon_maybe dict_tc dict_args-  = do { sv <- mkSysLocalM (fsLit "withDict_s") Many mty-       ; k  <- mkSysLocalM (fsLit "withDict_k") Many (mkInvisFunTyMany cls openAlphaTy)+  = do { sv <- mkSysLocalM (fsLit "withDict_s") ManyTy mty+       ; k  <- mkSysLocalM (fsLit "withDict_k") ManyTy (mkInvisFunTy cls openAlphaTy)         -- Given co2 : mty ~N# inst_meth_ty, construct the method of        -- the WithDict dictionary:@@ -472,11 +468,11 @@                mkCoreLams [ runtimeRep1TyVar, openAlphaTyVar, sv, k ] $                  Var nospecId                    `App`-                 (Type $ mkInvisFunTyMany cls openAlphaTy)+                 (Type $ mkInvisFunTy cls openAlphaTy)                    `App`                  Var k                    `App`-                 (Var sv `Cast` mkTcTransCo (mkTcSubCo co2) (mkTcSymCo co))+                 (Var sv `Cast` mkTransCo (mkSubCo co2) (mkSymCo co))         ; tc <- tcLookupTyCon withDictClassName        ; let Just withdict_data_con@@ -646,18 +642,29 @@ -- and it was applied to the correct argument. matchTypeable :: Class -> [Type] -> TcM ClsInstResult matchTypeable clas [k,t]  -- clas = Typeable-  -- For the first two cases, See Note [No Typeable for polytypes or qualified types]-  | isForAllTy k                      = return NoInstance   -- Polytype-  | isJust (tcSplitPredFunTy_maybe t) = return NoInstance   -- Qualified type+  -- Forall types: see Note [No Typeable for polytypes or qualified types]+  | isForAllTy k = return NoInstance +  -- Functions; but only with a visible argment+  | Just (af,mult,arg,ret) <- splitFunTy_maybe t+  = if isVisibleFunArg af+    then doFunTy clas t mult arg ret+    else return NoInstance+      -- 'else' case: qualified types like (Num a => blah) are not typeable+      -- see Note [No Typeable for polytypes or qualified types]+   -- Now cases that do work-  | k `eqType` naturalTy                   = doTyLit knownNatClassName         t-  | k `eqType` typeSymbolKind              = doTyLit knownSymbolClassName      t-  | k `eqType` charTy                      = doTyLit knownCharClassName        t-  | tcIsConstraintKind t                   = doTyConApp clas t constraintKindTyCon []-  | Just (mult,arg,ret) <- splitFunTy_maybe t   = doFunTy    clas t mult arg ret+  | k `eqType` naturalTy      = doTyLit knownNatClassName         t+  | k `eqType` typeSymbolKind = doTyLit knownSymbolClassName      t+  | k `eqType` charTy         = doTyLit knownCharClassName        t++  -- TyCon applied to its kind args+  -- No special treatment of Type and Constraint; they get distinct TypeReps+  -- see wrinkle (W4) of Note [Type and Constraint are not apart]+  --     in GHC.Builtin.Types.Prim.   | Just (tc, ks) <- splitTyConApp_maybe t -- See Note [Typeable (T a b c)]   , onlyNamedBndrsApplied tc ks            = doTyConApp clas t tc ks+   | Just (f,kt)   <- splitAppTy_maybe t    = doTyApp    clas t f kt  matchTypeable _ _ = return NoInstance@@ -681,10 +688,9 @@ doTyConApp :: Class -> Type -> TyCon -> [Kind] -> TcM ClsInstResult doTyConApp clas ty tc kind_args   | tyConIsTypeable tc-  = do-     return $ OneInst { cir_new_theta = (map (mk_typeable_pred clas) kind_args)-                      , cir_mk_ev     = mk_ev-                      , cir_what      = BuiltinTypeableInstance tc }+  = return $ OneInst { cir_new_theta = map (mk_typeable_pred clas) kind_args+                     , cir_mk_ev     = mk_ev+                     , cir_what      = BuiltinTypeableInstance tc }   | otherwise   = return NoInstance   where@@ -710,7 +716,7 @@ --    (Typeable f, Typeable Int, Typeable Char)  --> (after some simp. steps) --    Typeable f doTyApp clas ty f tk-  | isForAllTy (tcTypeKind f)+  | isForAllTy (typeKind f)   = return NoInstance -- We can't solve until we know the ctr.   | otherwise   = return $ OneInst { cir_new_theta = map (mk_typeable_pred clas) [f, tk]@@ -723,7 +729,7 @@  -- Emit a `Typeable` constraint for the given type. mk_typeable_pred :: Class -> Type -> PredType-mk_typeable_pred clas ty = mkClassPred clas [ tcTypeKind ty, ty ]+mk_typeable_pred clas ty = mkClassPred clas [ typeKind ty, ty ]    -- Typeable is implied by KnownNat/KnownSymbol. In the case of a type literal   -- we generate a sub-goal for the appropriate class.@@ -739,15 +745,32 @@  {- Note [Typeable (T a b c)] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ For type applications we always decompose using binary application,-via doTyApp, until we get to a *kind* instantiation.  Example-   Proxy :: forall k. k -> *+via doTyApp (building a TrApp), until we get to a *kind* instantiation+(building a TrTyCon).  We detect a pure kind instantiation using+`onlyNamedBndrsApplied`. -To solve Typeable (Proxy (* -> *) Maybe) we-  - First decompose with doTyApp,-    to get (Typeable (Proxy (* -> *))) and Typeable Maybe-  - Then solve (Typeable (Proxy (* -> *))) with doTyConApp+Example: Proxy :: forall k. k -> * +  To solve Typeable (Proxy @(* -> *) Maybe) we++  - First decompose with doTyApp (onlyNamedBndrsApplied is False)+    to get (Typeable (Proxy @(* -> *))) and Typeable Maybe.+    This step returns a TrApp.++  - Then solve (Typeable (Proxy @(* -> *))) with doTyConApp+    (onlyNamedBndrsApplied is True).+    This step returns a TrTyCon++  So the TypeRep we build is+    TrApp (TrTyCon ("Proxy" @(*->*))) (TrTyCon "Maybe")++Notice also that TYPE and CONSTRAINT are distinct so, in effect, we+allow (Typeable TYPE) and (Typeable CONSTRAINT), giving disinct TypeReps.+This is very important: we may want to get a TypeRep for a kind like+   Type -> Constraint+ If we attempt to short-cut by solving it all at once, via doTyConApp @@ -939,8 +962,8 @@                          -- it to a HasField dictionary.                          mk_ev (ev1:evs) = evSelector sel_id tvs evs `evCast` co                            where-                             co = mkTcSubCo (evTermCoercion (EvExpr ev1))-                                      `mkTcTransCo` mkTcSymCo co2+                             co = mkSubCo (evTermCoercion (EvExpr ev1))+                                      `mkTransCo` mkSymCo co2                          mk_ev [] = panic "matchHasField.mk_ev"                           Just (_, co2) = tcInstNewTyCon_maybe (classTyCon clas)
compiler/GHC/Tc/Instance/FunDeps.hs view
@@ -29,14 +29,18 @@ import GHC.Core.Class import GHC.Core.Predicate import GHC.Core.Type-import GHC.Tc.Utils.TcType( transSuperClasses )+import GHC.Core.RoughMap( RoughMatchTc(..) ) import GHC.Core.Coercion.Axiom( TypeEqn ) import GHC.Core.Unify import GHC.Core.InstEnv-import GHC.Types.Var.Set-import GHC.Types.Var.Env import GHC.Core.TyCo.FVs+import GHC.Core.TyCo.Compare( eqTypes, eqType ) import GHC.Core.TyCo.Ppr( pprWithExplicitKindsWhen )++import GHC.Tc.Utils.TcType( transSuperClasses )++import GHC.Types.Var.Set+import GHC.Types.Var.Env import GHC.Types.SrcLoc  import GHC.Utils.Outputable@@ -122,11 +126,12 @@        [W] D Int Bool ty      Then we'll generate-       FDEqn { fd_qtvs = [x], fd_eqs = [Pair x Bool, Pair (Maybe x) ty] }+       FDEqn { fd_qtvs = [x0], fd_eqs = [ x0 ~ Bool, Maybe x0 ~ ty] }+    which generates one fresh unification variable x0      But if the fundeps had been (a->b, a->c) we'd generate two FDEqns-       FDEqn { fd_qtvs = [x], fd_eqs = [Pair x Bool] }-       FDEqn { fd_qtvs = [x], fd_eqs = [Pair (Maybe x) ty] }+       FDEqn { fd_qtvs = [x1], fd_eqs = [ x1 ~ Bool ] }+       FDEqn { fd_qtvs = [x2], fd_eqs = [ Maybe x2 ~ ty ] }     with two FDEqns, generating two separate unification variables.  (3) improveFromInstEnv doesn't return any equations that already hold.@@ -405,7 +410,7 @@        where          (ls,rs) = instFD fd tyvars inst_taus          ls_tvs = tyCoVarsOfTypes ls-         rs_tvs = splitVisVarsOfTypes rs+         rs_tvs = visVarsOfTypes rs           undetermined_tvs | be_liberal = liberal_undet_tvs                           | otherwise  = conserv_undet_tvs
compiler/GHC/Tc/Instance/Typeable.hs view
@@ -13,7 +13,7 @@ import GHC.Prelude import GHC.Platform -import GHC.Types.Basic ( Boxity(..), neverInlinePragma )+import GHC.Types.Basic ( Boxity(..), TypeOrConstraint(..), neverInlinePragma ) import GHC.Types.SourceText ( SourceText(..) ) import GHC.Iface.Env( newGlobalBinder ) import GHC.Core.TyCo.Rep( Type(..), TyLit(..) )@@ -190,7 +190,7 @@ mkModIdBindings   = do { mod <- getModule        ; loc <- getSrcSpanM-       ; mod_nm        <- newGlobalBinder mod (mkVarOcc "$trModule") loc+       ; mod_nm        <- newGlobalBinder mod (mkVarOccFS (fsLit "$trModule")) loc        ; trModuleTyCon <- tcLookupTyCon trModuleTyConName        ; let mod_id = mkExportedVanillaId mod_nm (mkTyConApp trModuleTyCon [])        ; mod_bind      <- mkVarBind mod_id <$> mkModIdRHS mod@@ -330,9 +330,11 @@                       -- Build TypeRepTodos for built-in KindReps                    ; todo1 <- todoForExportedKindReps builtInKindReps+                      -- Build TypeRepTodos for types in GHC.Prim                    ; todo2 <- todoForTyCons gHC_PRIM ghc_prim_module_id                                             ghcPrimTypeableTyCons+                    ; return ( gbl_env' , [todo1, todo2])                    }            else do gbl_env <- getGblEnv@@ -406,7 +408,7 @@                 -> TypeableTyCon -> KindRepM (LHsBinds GhcTc) mkTyConRepBinds stuff todo (TypeableTyCon {..})   = do -- Make a KindRep-       let (bndrs, kind) = splitForAllTyCoVarBinders (tyConKind tycon)+       let (bndrs, kind) = splitForAllForAllTyBinders (tyConKind tycon)        liftTc $ traceTc "mkTyConKindRepBinds"                         (ppr tycon $$ ppr (tyConKind tycon) $$ ppr kind)        let ctx = mkDeBruijnContext (map binderVar bndrs)@@ -420,9 +422,8 @@ -- | Is a particular 'TyCon' representable by @Typeable@?. These exclude type -- families and polytypes. tyConIsTypeable :: TyCon -> Bool-tyConIsTypeable tc =-       isJust (tyConRepName_maybe tc)-    && kindIsTypeable (dropForAlls $ tyConKind tc)+tyConIsTypeable tc = isJust (tyConRepName_maybe tc)+                  && kindIsTypeable (dropForAlls $ tyConKind tc)  -- | Is a particular 'Kind' representable by @Typeable@? Here we look for -- polytypes and types containing casts (which may be, for instance, a type@@ -464,12 +465,14 @@ liftTc :: TcRn a -> KindRepM a liftTc = KindRepM . lift --- | We generate @KindRep@s for a few common kinds in @GHC.Types@ so that they+-- | We generate `KindRep`s for a few common kinds, so that they -- can be reused across modules.+-- These definitions are generated in `ghc-prim:GHC.Types`. builtInKindReps :: [(Kind, Name)] builtInKindReps =-    [ (star, starKindRepName)-    , (mkVisFunTyMany star star, starArrStarKindRepName)+    [ (star,                              starKindRepName)+    , (constraintKind,                    constraintKindRepName)+    , (mkVisFunTyMany star star,          starArrStarKindRepName)     , (mkVisFunTysMany [star, star] star, starArrStarArrStarKindRepName)     ]   where@@ -481,6 +484,7 @@     add_kind_rep acc (k,n) = do         id <- tcLookupId n         return $! extendTypeMap acc k (id, Nothing)+        -- The TypeMap looks through type synonyms  -- | Performed while compiling "GHC.Types" to generate the built-in 'KindRep's. mkExportedKindReps :: TypeableStuff@@ -496,6 +500,7 @@         -- since the latter would find the built-in 'KindRep's in the         -- 'KindRepEnv' (by virtue of being in 'initialKindRepEnv').         rhs <- mkKindRepRhs stuff empty_scope kind+        liftTc (traceTc "mkExport" (ppr kind $$ ppr rep_bndr $$ ppr rhs))         addKindRepBind empty_scope kind rep_bndr rhs  addKindRepBind :: CmEnv -> Kind -> Id -> LHsExpr GhcTc -> KindRepM ()@@ -528,10 +533,8 @@      go' :: Kind -> KindRepEnv -> TcRn (LHsExpr GhcTc, KindRepEnv)     go' k env-        -- Look through type synonyms-      | Just k' <- tcView k = go' k' env-         -- We've already generated the needed KindRep+        -- This lookup looks through synonyms       | Just (id, _) <- lookupTypeMapWithScope env in_scope k       = return (nlHsVar id, env) @@ -540,7 +543,7 @@       = do -- Place a NOINLINE pragma on KindReps since they tend to be quite            -- large and bloat interface files.            rep_bndr <- (`setInlinePragma` neverInlinePragma)-                   <$> newSysLocalId (fsLit "$krep") Many (mkTyConTy kindRepTyCon)+                   <$> newSysLocalId (fsLit "$krep") ManyTy (mkTyConTy kindRepTyCon)             -- do we need to tie a knot here?            flip runStateT env $ unKindRepM $ do@@ -560,24 +563,27 @@         -- We handle (TYPE LiftedRep) etc separately to make it         -- clear to consumers (e.g. serializers) that there is         -- a loop here (as TYPE :: RuntimeRep -> TYPE 'LiftedRep)-      | not (tcIsConstraintKind k)+      | Just (TypeLike, rep) <- sORTKind_maybe k               -- Typeable respects the Constraint/Type distinction               -- so do not follow the special case here-      , Just arg <- kindRep_maybe k-      = case splitTyConApp_maybe arg of-          Just (tc, [])+      = -- Here k = TYPE <something>+        case splitTyConApp_maybe rep of+          Just (tc, [])         -- TYPE IntRep, TYPE FloatRep etc             | Just dc <- isPromotedDataCon_maybe tc               -> return $ nlHsDataCon kindRepTYPEDataCon `nlHsApp` nlHsDataCon dc -          Just (rep, [levArg])-            | Just dcRep <- isPromotedDataCon_maybe rep-            , Just (lev, []) <- splitTyConApp_maybe levArg-            , Just dcLev <- isPromotedDataCon_maybe lev+          Just (rep_tc, [levArg])  -- TYPE (BoxedRep lev)+            | Just dcRep <- isPromotedDataCon_maybe rep_tc+            , Just (lev_tc, []) <- splitTyConApp_maybe levArg+            , Just dcLev <- isPromotedDataCon_maybe lev_tc               -> return $ nlHsDataCon kindRepTYPEDataCon `nlHsApp` (nlHsDataCon dcRep `nlHsApp` nlHsDataCon dcLev)            _   -> new_kind_rep k       | otherwise = new_kind_rep k +    new_kind_rep ki  -- Expand synonyms+      | Just ki' <- coreView ki+      = new_kind_rep ki'      new_kind_rep (TyVarTy v)       | Just idx <- lookupCME in_scope v@@ -649,7 +655,7 @@   where     n_kind_vars = length $ filter isNamedTyConBinder (tyConBinders tycon)     tycon_str = add_tick (occNameString (getOccName tycon))-    add_tick s | isPromotedDataCon tycon = '\'' : s+    add_tick s | isDataKindsPromotedDataCon tycon = '\'' : s                | otherwise               = s      -- This must match the computation done in
compiler/GHC/Tc/Module.hs view
@@ -121,7 +121,8 @@ import GHC.Core.Class import GHC.Core.Coercion.Axiom import GHC.Core.Reduction ( Reduction(..) )-import GHC.Core.Unify( RoughMatchTc(..) )+import GHC.Core.RoughMap( RoughMatchTc(..) )+import GHC.Core.TyCo.Ppr( debugPprType ) import GHC.Core.FamInstEnv    ( FamInst, pprFamInst, famInstsRepTyCons    , famInstEnvElts, extendFamInstEnvList, normaliseType )@@ -1095,6 +1096,7 @@        -- Order of pattern matching matters.        subDM _ Nothing _ = True        subDM _ _ Nothing = False+        -- If the hsig wrote:        --        --   f :: a -> a@@ -1102,11 +1104,14 @@        --        -- this should be validly implementable using an old-fashioned        -- vanilla default method.-       subDM t1 (Just (_, GenericDM t2)) (Just (_, VanillaDM))-        = eqTypeX env t1 t2+       subDM t1 (Just (_, GenericDM gdm_t1)) (Just (_, VanillaDM))+        = eqType t1 gdm_t1   -- Take care (#22476).  Both t1 and gdm_t1 come+                             -- from tc1, so use eqType, and /not/ eqTypeX+        -- This case can occur when merging signatures        subDM t1 (Just (_, VanillaDM)) (Just (_, GenericDM t2))         = eqTypeX env t1 t2+        subDM _ (Just (_, VanillaDM)) (Just (_, VanillaDM)) = True        subDM _ (Just (_, GenericDM t1)) (Just (_, GenericDM t2))         = eqTypeX env t1 t2@@ -1252,7 +1257,7 @@     --          data T a = MkT     --     -- If you write this, we'll treat T as injective, and make inferences-    -- like T a ~R T b ==> a ~N b (mkNthCo).  But if we can+    -- like T a ~R T b ==> a ~N b (mkSelCo).  But if we can     -- subsequently replace T with one at phantom role, we would then be able to     -- infer things like T Int ~R T Bool which is bad news.     --@@ -2717,7 +2722,8 @@                                normaliseType fam_envs Nominal ty                  | otherwise = ty -       ; return (ty', mkInfForAllTys kvs (tcTypeKind ty')) }+       ; traceTc "tcRnExpr" (debugPprType ty $$ debugPprType ty')+       ; return (ty', mkInfForAllTys kvs (typeKind ty')) }   {- Note [TcRnExprMode]
compiler/GHC/Tc/Solver.hs view
@@ -58,7 +58,7 @@ import GHC.Core.Type import GHC.Core.Ppr import GHC.Core.TyCon    ( TyConBinder, isTypeFamilyTyCon )-import GHC.Builtin.Types ( liftedRepTy, manyDataConTy, liftedDataConTy )+import GHC.Builtin.Types ( liftedRepTy, liftedDataConTy ) import GHC.Core.Unify    ( tcMatchTyKi ) import GHC.Utils.Misc import GHC.Utils.Panic@@ -2895,7 +2895,7 @@        ; return True }   | isMultiplicityVar the_tv   = do { traceTcS "defaultTyVarTcS Multiplicity" (ppr the_tv)-       ; unifyTyVar the_tv manyDataConTy+       ; unifyTyVar the_tv ManyTy        ; return True }   | otherwise   = return False  -- the common case@@ -2996,7 +2996,7 @@      foo x = show (\_ -> True)  Then we'll get a constraint (Show (p ->q)) where p has kind (TYPE r),-and that won't match the tcTypeKind (*) in the instance decl.  See tests+and that won't match the typeKind (*) in the instance decl.  See tests tc217 and tc175.  We look only at touchable type variables. No further constraints@@ -3153,7 +3153,7 @@         | Just (cls,tys)   <- getClassPredTys_maybe (ctPred cc)         , [ty] <- filterOutInvisibleTypes (classTyCon cls) tys               -- Ignore invisible arguments for this purpose-        , Just tv <- tcGetTyVar_maybe ty+        , Just tv <- getTyVar_maybe ty         , isMetaTyVar tv  -- We might have runtime-skolems in GHCi, and                           -- we definitely don't want to try to assign to those!         = Left (cc, cls, tv)
compiler/GHC/Tc/Solver/Canonical.hs view
@@ -52,6 +52,7 @@ import GHC.Utils.Misc import GHC.Data.Bag import GHC.Utils.Monad+import GHC.Utils.Constants( debugIsOn ) import Control.Monad import Data.Maybe ( isJust, isNothing ) import Data.List  ( zip4 )@@ -112,10 +113,9 @@     --    e.g. a ~ [a], where [G] a ~ [Int], can decompose  canonicalize (CDictCan { cc_ev = ev, cc_class  = cls-                       , cc_tyargs = xis, cc_pend_sc = pend_sc-                       , cc_fundeps = fds })+                       , cc_tyargs = xis, cc_pend_sc = pend_sc })   = {-# SCC "canClass" #-}-    canClass ev cls xis pend_sc fds+    canClass ev cls xis pend_sc  canonicalize (CEqCan { cc_ev     = ev                      , cc_lhs    = lhs@@ -155,7 +155,7 @@   | isGiven ev  -- See Note [Eagerly expand given superclasses]   = do { sc_cts <- mkStrictSuperClasses ev [] [] cls tys        ; emitWork sc_cts-       ; canClass ev cls tys False fds }+       ; canClass ev cls tys False }    | CtWanted { ctev_rewriters = rewriters } <- ev   , Just ip_name <- isCallStackPred cls tys@@ -181,20 +181,17 @@                                   (ctLocSpan loc) (ctEvExpr new_ev)        ; solveCallStack ev ev_cs -       ; canClass new_ev cls tys-                  False -- No superclasses-                  False -- No top level instances for fundeps+       ; canClass new_ev cls tys False -- No superclasses        }    | otherwise-  = canClass ev cls tys (has_scs cls) fds+  = canClass ev cls tys (has_scs cls)    where     has_scs cls = not (null (classSCTheta cls))     loc  = ctEvLoc ev     orig = ctLocOrigin loc     pred = ctEvPred ev-    fds  = classHasFds cls  solveCallStack :: CtEvidence -> EvCallStack -> TcS () -- Also called from GHC.Tc.Solver when defaulting call stacks@@ -209,11 +206,10 @@ canClass :: CtEvidence          -> Class -> [Type]          -> Bool            -- True <=> un-explored superclasses-         -> Bool            -- True <=> unexploited fundep(s)          -> TcS (StopOrContinue Ct) -- Precondition: EvVar is class evidence -canClass ev cls tys pend_sc fds+canClass ev cls tys pend_sc   = -- all classes do *nominal* matching     assertPpr (ctEvRole ev == Nominal) (ppr ev $$ ppr cls $$ ppr tys) $     do { (redns@(Reductions _ xis), rewriters) <- rewriteArgsNom ev cls_tc tys@@ -221,8 +217,7 @@              mk_ct new_ev = CDictCan { cc_ev = new_ev                                      , cc_tyargs = xis                                      , cc_class = cls-                                     , cc_pend_sc = pend_sc-                                     , cc_fundeps = fds }+                                     , cc_pend_sc = pend_sc }        ; mb <- rewriteEvidence rewriters ev redn        ; traceTcS "canClass" (vcat [ ppr ev                                    , ppr xi, ppr mb ])@@ -670,7 +665,7 @@      this_ct | null tvs, null theta             = CDictCan { cc_ev = ev, cc_class = cls, cc_tyargs = tys-                       , cc_pend_sc = loop_found, cc_fundeps = classHasFds cls }+                       , cc_pend_sc = loop_found }                  -- NB: If there is a loop, we cut off, so we have not                  --     added the superclasses, hence cc_pend_sc = True             | otherwise@@ -942,23 +937,30 @@      FunTy (a :: k) Int -Where k is a unification variable. So the calls to getRuntimeRep_maybe may+Where k is a unification variable. So the calls to splitRuntimeRep_maybe may fail (returning Nothing).  In that case we'll fall through, zonk, and try again. Zonking should fill the variable k, meaning that decomposition will succeed the second time around. -Also note that we require the AnonArgFlag to match.  This will stop+Also note that we require the FunTyFlag to match.  This will stop us decomposing    (Int -> Bool)  ~  (Show a => blah)-It's as if we treat (->) and (=>) as different type constructors.+It's as if we treat (->) and (=>) as different type constructors, which+indeed they are! -}  canEqNC :: CtEvidence -> EqRel -> Type -> Type -> TcS (StopOrContinue Ct) canEqNC ev eq_rel ty1 ty2   = do { result <- zonk_eq_types ty1 ty2        ; case result of-           Left (Pair ty1' ty2') -> can_eq_nc False ev eq_rel ty1' ty1 ty2' ty2-           Right ty              -> canEqReflexive ev eq_rel ty }+           Right ty              -> canEqReflexive ev eq_rel ty+           Left (Pair ty1' ty2') -> can_eq_nc False ev' eq_rel ty1' ty1' ty2' ty2'+             where+               ev' | debugIsOn = setCtEvPredType ev $+                                 mkPrimEqPredRole (eqRelRole eq_rel) ty1' ty2'+                   | otherwise = ev+                   -- ev': satisfy the precondition of can_eq_nc+       }  can_eq_nc    :: Bool            -- True => both types are rewritten@@ -967,6 +969,11 @@    -> Type -> Type    -- LHS, after and before type-synonym expansion, resp    -> Type -> Type    -- RHS, after and before type-synonym expansion, resp    -> TcS (StopOrContinue Ct)+-- Precondition: in DEBUG mode, the `ctev_pred` of `ev` is (ps_ty1 ~# ps_ty2),+--               without zonking+-- This precondition is needed (only in DEBUG) to satisfy the assertions+--   in mkSelCo, called in canDecomposableTyConAppOK and canDecomposableFunTy+ can_eq_nc rewritten ev eq_rel ty1 ps_ty1 ty2 ps_ty2   = do { traceTcS "can_eq_nc" $          vcat [ ppr rewritten, ppr ev, ppr eq_rel, ppr ty1, ppr ps_ty1, ppr ty2, ppr ps_ty2 ]@@ -991,8 +998,8 @@  -- Expand synonyms first; see Note [Type synonyms and canonicalization] can_eq_nc' rewritten rdr_env envs ev eq_rel ty1 ps_ty1 ty2 ps_ty2-  | Just ty1' <- tcView ty1 = can_eq_nc' rewritten rdr_env envs ev eq_rel ty1' ps_ty1 ty2  ps_ty2-  | Just ty2' <- tcView ty2 = can_eq_nc' rewritten rdr_env envs ev eq_rel ty1  ps_ty1 ty2' ps_ty2+  | Just ty1' <- coreView ty1 = can_eq_nc' rewritten rdr_env envs ev eq_rel ty1' ps_ty1 ty2  ps_ty2+  | Just ty2' <- coreView ty2 = can_eq_nc' rewritten rdr_env envs ev eq_rel ty1  ps_ty1 ty2' ps_ty2  -- need to check for reflexivity in the ReprEq case. -- See Note [Eager reflexivity check]@@ -1037,14 +1044,8 @@ can_eq_nc' _rewritten _rdr_env _envs ev eq_rel            (FunTy { ft_mult = am1, ft_af = af1, ft_arg = ty1a, ft_res = ty1b }) _ps_ty1            (FunTy { ft_mult = am2, ft_af = af2, ft_arg = ty2a, ft_res = ty2b }) _ps_ty2-  | af1 == af2   -- Don't decompose (Int -> blah) ~ (Show a => blah)-  , Just ty1a_rep <- getRuntimeRep_maybe ty1a  -- getRutimeRep_maybe:-  , Just ty1b_rep <- getRuntimeRep_maybe ty1b  -- see Note [Decomposing FunTy]-  , Just ty2a_rep <- getRuntimeRep_maybe ty2a-  , Just ty2b_rep <- getRuntimeRep_maybe ty2b-  = canDecomposableTyConAppOK ev eq_rel funTyCon-                              [am1, ty1a_rep, ty1b_rep, ty1a, ty1b]-                              [am2, ty2a_rep, ty2b_rep, ty2a, ty2b]+  | af1 == af2  -- See Note [Decomposing FunTy]+  = canDecomposableFunTy ev eq_rel af1 (am1,ty1a,ty1b) (am2,ty2a,ty2b)  -- Decompose type constructor applications -- NB: we have expanded type synonyms already@@ -1061,12 +1062,13 @@ can_eq_nc' _rewritten _rdr_env _envs ev eq_rel            s1@(ForAllTy (Bndr _ vis1) _) _            s2@(ForAllTy (Bndr _ vis2) _) _-  | vis1 `sameVis` vis2 -- Note [ForAllTy and typechecker equality]+  | vis1 `eqForAllVis` vis2 -- Note [ForAllTy and type equality]   = can_eq_nc_forall ev eq_rel s1 s2  -- See Note [Canonicalising type applications] about why we require rewritten types -- Use tcSplitAppTy, not matching on AppTy, to catch oversaturated type families--- NB: Only decompose AppTy for nominal equality. See Note [Decomposing equality]+-- NB: Only decompose AppTy for nominal equality.+--     See Note [Decomposing AppTy equalities] can_eq_nc' True _rdr_env _envs ev NomEq ty1 _ ty2 _   | Just (t1, s1) <- tcSplitAppTy_maybe ty1   , Just (t2, s2) <- tcSplitAppTy_maybe ty2@@ -1126,63 +1128,6 @@ that is not necessarily insoluble!  Maybe 'a' will turn out to be a newtype. So we want to make it a potentially-soluble Irred not an insoluble one. Missing this point is what caused #15431--Note [ForAllTy and typechecker equality]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Should GHC type-check the following program (adapted from #15740)?--  {-# LANGUAGE PolyKinds, ... #-}-  data D a-  type family F :: forall k. k -> Type-  type instance F = D--Due to the way F is declared, any instance of F must have a right-hand side-whose kind is equal to `forall k. k -> Type`. The kind of D is-`forall {k}. k -> Type`, which is very close, but technically uses distinct-Core:--  ------------------------------------------------------------  | Source Haskell    | Core                                |-  ------------------------------------------------------------  | forall  k.  <...> | ForAllTy (Bndr k Specified) (<...>) |-  | forall {k}. <...> | ForAllTy (Bndr k Inferred)  (<...>) |-  -------------------------------------------------------------We could deem these kinds to be unequal, but that would imply rejecting-programs like the one above. Whether a kind variable binder ends up being-specified or inferred can be somewhat subtle, however, especially for kinds-that aren't explicitly written out in the source code (like in D above).-For now, we decide to not make the specified/inferred status of an invisible-type variable binder affect GHC's notion of typechecker equality-(see Note [Typechecker equality vs definitional equality] in-GHC.Tc.Utils.TcType). That is, we have the following:--  ---------------------------------------------------  | Type 1            | Type 2            | Equal? |-  --------------------|------------------------------  | forall k. <...>   | forall k. <...>   | Yes    |-  |                   | forall {k}. <...> | Yes    |-  |                   | forall k -> <...> | No     |-  ---------------------------------------------------  | forall {k}. <...> | forall k. <...>   | Yes    |-  |                   | forall {k}. <...> | Yes    |-  |                   | forall k -> <...> | No     |-  ---------------------------------------------------  | forall k -> <...> | forall k. <...>   | No     |-  |                   | forall {k}. <...> | No     |-  |                   | forall k -> <...> | Yes    |-  ----------------------------------------------------We implement this nuance by using the GHC.Types.Var.sameVis function in-GHC.Tc.Solver.Canonical.canEqNC and GHC.Tc.Utils.TcType.tcEqType, which-respect typechecker equality. sameVis puts both forms of invisible type-variable binders into the same equivalence class.--Note that we do /not/ use sameVis in GHC.Core.Type.eqType, which implements-/definitional/ equality, a slightly more coarse-grained notion of equality-(see Note [Non-trivial definitional equality] in GHC.Core.TyCo.Rep) that does-not consider the ArgFlag of ForAllTys at all. That is, eqType would equate all-of forall k. <...>, forall {k}. <...>, and forall k -> <...>. -}  ---------------------------------@@ -1205,8 +1150,8 @@       ; if not (equalLength bndrs1 bndrs2)         then do { traceTcS "Forall failure" $                      vcat [ ppr s1, ppr s2, ppr bndrs1, ppr bndrs2-                          , ppr (map binderArgFlag bndrs1)-                          , ppr (map binderArgFlag bndrs2) ]+                          , ppr (binderFlags bndrs1)+                          , ppr (binderFlags bndrs2) ]                 ; canEqHardFailure ev s1 s2 }         else    do { traceTcS "Creating implication for polytype equality" $ ppr ev@@ -1229,7 +1174,7 @@                          -- skol_tv is already in the in-scope set, but the                          -- free vars of kind_co are not; hence "...AndInScope"                    ; (co, wanteds2) <- go skol_tvs subst' bndrs2-                   ; return ( mkTcForAllCo skol_tv kind_co co+                   ; return ( mkForAllCo skol_tv kind_co co                             , wanteds1 `unionBags` wanteds2 ) }              -- Done: unify phi1 ~ phi2@@ -1259,7 +1204,7 @@     -- than putting it in the work list     unify loc rewriters role ty1 ty2       | ty1 `tcEqType` ty2-      = return (mkTcReflCo role ty1, emptyBag)+      = return (mkReflCo role ty1, emptyBag)       | otherwise       = do { (wanted, co) <- newWantedEq loc rewriters role ty1 ty2            ; return (co, unitBag (mkNonCanonical wanted)) }@@ -1295,23 +1240,19 @@     -- so we may run into an unzonked type variable while trying to compute the     -- RuntimeReps of the argument and result types. This can be observed in     -- testcase tc269.-    go ty1 ty2-      | Just (Scaled w1 arg1, res1) <- split1-      , Just (Scaled w2 arg2, res2) <- split2+    go (FunTy af1 w1 arg1 res1) (FunTy af2 w2 arg2 res2)+      | af1 == af2       , eqType w1 w2       = do { res_a <- go arg1 arg2            ; res_b <- go res1 res2-           ; return $ combine_rev (mkVisFunTy w1) res_b res_a-           }-      | isJust split1 || isJust split2-      = bale_out ty1 ty2-      where-        split1 = tcSplitFunTy_maybe ty1-        split2 = tcSplitFunTy_maybe ty2+           ; return $ combine_rev (FunTy af1 w1) res_b res_a } +    go ty1@(FunTy {}) ty2 = bale_out ty1 ty2+    go ty1 ty2@(FunTy {}) = bale_out ty1 ty2+     go ty1 ty2-      | Just (tc1, tys1) <- tcRepSplitTyConApp_maybe ty1-      , Just (tc2, tys2) <- tcRepSplitTyConApp_maybe ty2+      | Just (tc1, tys1) <- splitTyConAppNoView_maybe ty1+      , Just (tc2, tys2) <- splitTyConAppNoView_maybe ty2       = if tc1 == tc2 && tys1 `equalLength` tys2           -- Crucial to check for equal-length args, because           -- we cannot assume that the two args to 'go' have@@ -1323,8 +1264,8 @@         else bale_out ty1 ty2      go ty1 ty2-      | Just (ty1a, ty1b) <- tcRepSplitAppTy_maybe ty1-      , Just (ty2a, ty2b) <- tcRepSplitAppTy_maybe ty2+      | Just (ty1a, ty1b) <- tcSplitAppTyNoView_maybe ty1+      , Just (ty2a, ty2b) <- tcSplitAppTyNoView_maybe ty2       = do { res_a <- go ty1a ty2a            ; res_b <- go ty1b ty2b            ; return $ combine_rev mkAppTy res_b res_a }@@ -1404,6 +1345,8 @@  {- See Note [Unwrap newtypes first] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See also Note [Decomposing newtype equalities]+ Consider   newtype N m a = MkN (m a) Then N will get a conservative, Nominal role for its second parameter 'a',@@ -1517,7 +1460,7 @@  -- AppTys only decompose for nominal equality, so this case just leads -- to an irreducible constraint; see typecheck/should_compile/T10494--- See Note [Decomposing AppTy at representational role]+-- See Note [Decomposing AppTy equalities] can_eq_app ev s1 t1 s2 t2   | CtWanted { ctev_dest = dest, ctev_rewriters = rewriters } <- ev   = do { co_s <- unifyWanted rewriters loc Nominal s1 s2@@ -1538,9 +1481,9 @@   = canEqHardFailure ev (s1 `mkAppTy` t1) (s2 `mkAppTy` t2)    | CtGiven { ctev_evar = evar } <- ev-  = do { let co   = mkTcCoVarCo evar-             co_s = mkTcLRCo CLeft  co-             co_t = mkTcLRCo CRight co+  = do { let co   = mkCoVarCo evar+             co_s = mkLRCo CLeft  co+             co_t = mkLRCo CRight co        ; evar_s <- newGivenEvVar loc ( mkTcEqPredLikeEv ev s1 s2                                      , evCoercion co_s )        ; evar_t <- newGivenEvVar loc ( mkTcEqPredLikeEv ev t1 t2@@ -1551,8 +1494,8 @@   where     loc = ctEvLoc ev -    s1k = tcTypeKind s1-    s2k = tcTypeKind s2+    s1k = typeKind s1+    s2k = typeKind s2      k1 `mismatches` k2       =  isForAllTy k1 && not (isForAllTy k2)@@ -1584,8 +1527,10 @@             -> TyCon -> [TcType]             -> TyCon -> [TcType]             -> TcS (StopOrContinue Ct)--- See Note [Decomposing TyConApps]--- Neither tc1 nor tc2 is a saturated funTyCon+-- See Note [Decomposing TyConApp equalities]+-- See Note [Decomposing Dependent TyCons and Processing Wanted Equalities]+-- Neither tc1 nor tc2 is a saturated funTyCon, nor a type family+-- But they can be data families. canTyConApp ev eq_rel tc1 tys1 tc2 tys2   | tc1 == tc2   , tys1 `equalLength` tys2@@ -1604,23 +1549,28 @@   | eq_rel == ReprEq && not (isGenerativeTyCon tc1 Representational &&                              isGenerativeTyCon tc2 Representational)   = canEqFailure ev eq_rel ty1 ty2+   | otherwise   = canEqHardFailure ev ty1 ty2   where     -- Reconstruct the types for error messages. This would do     -- the wrong thing (from a pretty printing point of view)-    -- for functions, because we've lost the AnonArgFlag; but+    -- for functions, because we've lost the FunTyFlag; but     -- in fact we never call canTyConApp on a saturated FunTyCon     ty1 = mkTyConApp tc1 tys1     ty2 = mkTyConApp tc2 tys2 -    loc  = ctEvLoc ev-    pred = ctEvPred ev--     -- See Note [Decomposing equality]+     -- See Note [Decomposing TyConApp equalities]+     -- Note [Decomposing newtypes a bit more aggressively]     can_decompose inerts       =  isInjectiveTyCon tc1 (eqRelRole eq_rel)-      || (ctEvFlavour ev /= Given && isEmptyBag (matchableGivens loc pred inerts))+      || (assert (eq_rel == ReprEq) $+          -- assert: isInjectiveTyCon is always True for Nominal except+          --   for type synonyms/families, neither of which happen here+          -- Moreover isInjectiveTyCon is True for Representational+          --   for algebraic data types.  So we are down to newtypes+          --   and data families.+          ctEvFlavour ev == Wanted && noGivenIrreds inerts)  {- Note [Use canEqFailure in canDecomposableTyConApp]@@ -1654,219 +1604,330 @@ That should compile, but only because we use canEqFailure and not canEqHardFailure. -Note [Decomposing equality]-~~~~~~~~~~~~~~~~~~~~~~~~~~~-If we have a constraint (of any flavour and role) that looks like-T tys1 ~ T tys2, what can we conclude about tys1 and tys2? The answer,-of course, is "it depends". This Note spells it all out.+Note [Fast path when decomposing TyConApps]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we see (T s1 t1 ~ T s2 t2), then we can just decompose to+  (s1 ~ s2, t1 ~ t2)+and push those back into the work list.  But if+  s1 = K k1    s2 = K k2+then we will just decompose s1~s2, and it might be better to+do so on the spot.  An important special case is where s1=s2,+and we get just Refl. -In this Note, "decomposition" refers to taking the constraint-  [fl] (T tys1 ~X T tys2)-(for some flavour fl and some role X) and replacing it with-  [fls'] (tys1 ~Xs' tys2)-where that notation indicates a list of new constraints, where the-new constraints may have different flavours and different roles.+So canDecomposableTyConAppOK uses unifyWanted etc to short-cut that work.+See also Note [Decomposing Dependent TyCons and Processing Wanted Equalities] -The key property to consider is injectivity. When decomposing a Given, the-decomposition is sound if and only if T is injective in all of its type-arguments. When decomposing a Wanted, the decomposition is sound (assuming the-correct roles in the produced equality constraints), but it may be a guess ---that is, an unforced decision by the constraint solver. Decomposing Wanteds-over injective TyCons does not entail guessing. But sometimes we want to-decompose a Wanted even when the TyCon involved is not injective! (See below.)+Note [Decomposing TyConApp equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have+        [G/W] T ty1 ~r T ty2+Can we decompose it, and replace it by+        [G/W] ty1 ~r' ty2+and if so what role is r'?  (In this Note, all the "~" are primitive+equalities "~#", but I have dropped the noisy "#" symbols.)  Lots of+background in the paper "Safe zero-cost coercions for Haskell". -So, in broad strokes, we want this rule:+This Note covers the topic for+  * Datatypes+  * Newtypes+  * Data families+For the rest:+  * Type synonyms: are always expanded+  * Type families: see Note [Decomposing type family applications]+  * AppTy:         see Note [Decomposing AppTy equalities]. -(*) Decompose a constraint (T tys1 ~X T tys2) if and only if T is injective-at role X.+---- Roles of the decomposed constraints ----+For a start, the role r' will always be defined like this:+  * If r=N then r' = N+  * If r=R then r' = role of T's first argument -Pursuing the details requires exploring three axes:-* Flavour: Given vs. Wanted-* Role: Nominal vs. Representational-* TyCon species: datatype vs. newtype vs. data family vs. type family vs. type variable+For example:+   data TR a = MkTR a       -- Role of T's first arg is Representational+   data TN a = MkTN (F a)   -- Role of T's first arg is Nominal -(A type variable isn't a TyCon, of course, but it's convenient to put the AppTy case-in the same table.)+The function tyConRolesX :: Role -> TyCon -> [Role] gets the argument+role r' for a TyCon T at role r.  E.g.+   tyConRolesX Nominal          TR = [Nominal]+   tyConRolesX Representational TR = [Representational] -Here is a table (discussion following) detailing where decomposition of-   (T s1 ... sn) ~r (T t1 .. tn)-is allowed.  The first four lines (Data types ... type family) refer-to TyConApps with various TyCons T; the last line is for AppTy, covering-both where there is a type variable at the head and the case for an over--saturated type family.+---- Soundness and completeness ----+For Givens, for /soundness/ of decomposition we need, forall ty1,ty2:+    T ty1 ~r T ty2   ===>    ty1 ~r' ty2+Here "===>" means "implies".  That is, given evidence for (co1 : T ty1 ~r T co2)+we can produce evidence for (co2 : ty1 ~r' ty2).  But in the solver we+/replace/ co1 with co2 in the inert set, and we don't want to lose any proofs+thereby. So for /completeness/ of decomposition we also need the reverse:+    ty1 ~r' ty2   ===>    T ty1 ~r T ty2 -NOMINAL               GIVEN        WANTED                         WHERE+For Wanteds, for /soundness/ of decomposition we need:+    ty1 ~r' ty2   ===>    T ty1 ~r T ty2+because if we do decompose we'll get evidence (co2 : ty1 ~r' ty2) and+from that we want to derive evidence (T co2 : T ty1 ~r T ty2).+For /completeness/ of decomposition we need the reverse implication too,+else we may decompose to a new proof obligation that is stronger than+the one we started with.  See Note [Decomposing newtype equalities]. -Datatype               YES          YES                           canTyConApp-Newtype                YES          YES                           canTyConApp-Data family            YES          YES                           canTyConApp-Type family            NO{1}        YES, in injective args{1}     canEqCanLHS2-AppTy                  YES          YES                           can_eq_app+---- Injectivity ----+When do these bi-implications hold? In one direction it is easy.+We /always/ have+    ty1 ~r'  ty2   ===>    T ty1 ~r T ty2+This is the CO_TYCONAPP rule of the paper (Fig 5); see also the+TyConAppCo case of GHC.Core.Lint.lintCoercion. -REPRESENTATIONAL      GIVEN        WANTED+In the other direction, we have+    T ty1 ~r T ty2   ==>   ty1 ~r' ty2  if T is /injective at role r/+This is the very /definition/ of injectivity: injectivity means result+is the same => arguments are the same, modulo the role shift.+See comments on GHC.Core.TyCon.isInjectiveTyCon.  This is also+the CO_NTH rule in Fig 5 of the paper, except in the paper only+newtypes are non-injective at representation role, so the rule says "H+is not a newtype". -Datatype               YES          YES                           canTyConApp-Newtype                NO{2}       MAYBE{2}                canTyConApp(can_decompose)-Data family            NO{3}       MAYBE{3}                canTyConApp(can_decompose)-Type family            NO           NO                            canEqCanLHS2-AppTy                  NO{4}        NO{4}                         can_eq_nc'+Injectivity is a bit subtle:+                 Nominal   Representational+   Datatype        YES        YES+   Newtype         YES        NO{1}+   Data family     YES        NO{2} -{1}: Type families can be injective in some, but not all, of their arguments,-so we want to do partial decomposition. This is quite different than the way-other decomposition is done, where the decomposed equalities replace the original-one. We thus proceed much like we do with superclasses, emitting new Wanteds-when "decomposing" a partially-injective type family Wanted. Injective type-families have no corresponding evidence of their injectivity, so we cannot-decompose an injective-type-family Given.+{1} Consider newtype N a = MkN (F a)   -- Arg has Nominal role+    Is it true that (N t1) ~R (N t2)   ==>   t1 ~N t2  ?+    No, absolutely not.  E.g.+       type instance F Int = Int; type instance F Bool = Char+       Then (N Int) ~R (N Bool), by unwrapping, but we don't want Int~Char! -{2}: See Note [Decomposing newtypes at representational role]+    See Note [Decomposing newtype equalities] -{3}: Because of the possibility of newtype instances, we must treat-data families like newtypes. See also-Note [Decomposing newtypes at representational role]. See #10534 and-test case typecheck/should_fail/T10534.+{2} We must treat data families precisely like newtypes, because of the+    possibility of newtype instances. See also+    Note [Decomposing newtype equalities]. See #10534 and+    test case typecheck/should_fail/T10534. -{4}: See Note [Decomposing AppTy at representational role]+---- Takeaway summary -----+For sound and complete decomposition, we simply need injectivity;+that is for isInjectiveTyCon to be true: -   Because type variables can stand in for newtypes, we conservatively do not-   decompose AppTys over representational equality. Here are two examples that-   demonstrate why we can't:+* At Nominal role, isInjectiveTyCon is True for all the TyCons we are+  considering in this Note: datatypes, newtypes, and data families. -   4a: newtype Phant a = MkPhant Int-       [W] alpha Int ~R beta Bool+* For Givens, injectivity is necessary for soundness; completeness has no+  side conditions. -   If we eventually solve alpha := Phant and beta := Phant, then we can solve-   this equality by unwrapping. But it would have been disastrous to decompose-   the wanted to produce Int ~ Bool, which is definitely insoluble.+* For Wanteds, soundness has no side conditions; but injectivity is needed+  for completeness. See Note [Decomposing newtype equalities] -   4b: newtype Age = MkAge Int-       [W] alpha Age ~R Maybe Int+This is implemented in `can_decompose` in `canTyConApp`; it looks at+injectivity, just as specified above. -   First, a question: if we know that ty1 ~R ty2, can we conclude that-   a ty1 ~R a ty2? Not for all a. This is precisely why we need role annotations-   on type constructors. So, if we were to decompose, we would need to-   decompose to [W] alpha ~R Maybe and [W] Age ~ Int. On the other hand, if we-   later solve alpha := Maybe, then we would decompose to [W] Age ~R Int, and-   that would be soluble. -In the implementation of can_eq_nc and friends, we don't directly pattern-match using lines like in the tables above, as those tables don't cover-all cases (what about PrimTyCon? tuples?). Instead we just ask about injectivity,-boiling the tables above down to rule (*). The exceptions to rule (*) are for-injective type families, which are handled separately from other decompositions,-and the MAYBE entries above.+Note [Decomposing type family applications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Supose we have+   [G/W]  (F ty1) ~r  (F ty2)+This is handled by the TyFamLHS/TyFamLHS case of canEqCanLHS2. -Note [Decomposing newtypes at representational role]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-This note discusses the 'newtype' line in the REPRESENTATIONAL table-in Note [Decomposing equality]. (At nominal role, newtypes are fully-decomposable.)+We never decompose to+   [G/W]  ty1 ~r' ty2 -Here is a representative example of why representational equality over-newtypes is tricky:+Instead -  newtype Nt a = Mk Bool         -- NB: a is not used in the RHS,-  type role Nt representational  -- but the user gives it an R role anyway+* For Givens we do nothing. Injective type families have no corresponding+  evidence of their injectivity, so we cannot decompose an+  injective-type-family Given. -If we have [W] Nt alpha ~R Nt beta, we *don't* want to decompose to-[W] alpha ~R beta, because it's possible that alpha and beta aren't-representationally equal. Here's another example.+* For Wanteds, for the Nominal role only, we emit new Wanteds rather like+  functional dependencies, for each injective argument position. -  newtype Nt a = MkNt (Id a)-  type family Id a where Id a = a+  E.g type family F a b   -- injective in first arg, but not second+      [W] (F s1 t1) ~N (F s2 t2)+  Emit new Wanteds+      [W] s1 ~N s2+  But retain the existing, unsolved constraint. -  [W] Nt Int ~R Nt Age+Note [Decomposing newtype equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This Note also applies to data families, which we treat like+newtype in case of 'newtype instance'. -Because of its use of a type family, Nt's parameter will get inferred to have-a nominal role. Thus, decomposing the wanted will yield [W] Int ~N Age, which-is unsatisfiable. Unwrapping, though, leads to a solution.+As Note [Decomposing TyConApp equalities] describes, if N is injective+at role r, we can do this decomposition?+   [G/W] (N ty1) ~r (N ty2)    to     [G/W]  ty1 ~r' ty2 -Conclusion:- * Unwrap newtypes before attempting to decompose them.-   This is done in can_eq_nc'.+For a Given with r=R, the answer is a solid NO: newtypes are not injective at+representational role, and we must not decompose, or we lose soundness.+Example is wrinkle {1} in Note [Decomposing TyConApp equalities]. -It all comes from the fact that newtypes aren't necessarily injective-w.r.t. representational equality.+For a Wanted with r=R, since newtypes are not injective at representational+role, decomposition is sound, but we may lose completeness.  Nevertheless,+if the newtype is abstraction (so can't be unwrapped) we can only solve+the equality by (a) using a Given or (b) decomposition.  If (a) is impossible+(e.g. no Givens) then (b) is safe. -Furthermore, as explained in Note [NthCo and newtypes] in GHC.Core.TyCo.Rep, we can't use-NthCo on representational coercions over newtypes. NthCo comes into play-only when decomposing givens.+Conclusion: decompose newtypes (at role R) only if there are no usable Givens. -Conclusion:- * Do not decompose [G] N s ~R N t+* Incompleteness example (EX1)+      newtype Nt a = MkNt (Id a)+      type family Id a where Id a = a -Is it sensible to decompose *Wanted* constraints over newtypes?  Yes!-It's the only way we could ever prove (IO Int ~R IO Age), recalling-that IO is a newtype.+      [W] Nt Int ~R Nt Age -However we must be careful.  Consider+  Because of its use of a type family, Nt's parameter will get inferred to+  have a nominal role. Thus, decomposing the wanted will yield [W] Int ~N Age,+  which is unsatisfiable. Unwrapping, though, leads to a solution. -  type role Nt representational+  Conclusion: always unwrap newtypes before attempting to decompose+  them.  This is done in can_eq_nc'.  Of course, we can't unwrap if the data+  constructor isn't in scope.  See See Note [Unwrap newtypes first]. -  [G] Nt a ~R Nt b       (1)-  [W] NT alpha ~R Nt b   (2)-  [W] alpha ~ a          (3)+* Incompleteness example (EX2)+      newtype Nt a = Mk Bool         -- NB: a is not used in the RHS,+      type role Nt representational  -- but the user gives it an R role anyway -If we focus on (3) first, we'll substitute in (2), and now it's-identical to the given (1), so we succeed.  But if we focus on (2)-first, and decompose it, we'll get (alpha ~R b), which is not soluble.-This is exactly like the question of overlapping Givens for class-constraints: see Note [Instance and Given overlap] in GHC.Tc.Solver.Interact.+  If we have [W] Nt alpha ~R Nt beta, we *don't* want to decompose to+  [W] alpha ~R beta, because it's possible that alpha and beta aren't+  representationally equal. -Conclusion:-  * Decompose [W] N s ~R N t  iff there no given constraint that could-    later solve it.+  and maybe there is a Given (Nt t1 ~R Nt t2), just waiting to be used, if we+  figure out (elsewhere) that alpha:=t1 and beta:=t2.  This is somewhat+  similar to the question of overlapping Givens for class constraints: see+  Note [Instance and Given overlap] in GHC.Tc.Solver.Interact. -Note [Decomposing AppTy at representational role]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-We never decompose AppTy at a representational role. For Givens, doing-so is simply unsound: the LRCo coercion former requires a nominal-roled-arguments. (See (1) for an example of why.) For Wanteds, decomposing-would be sound, but it would be a guess, and a non-confluent one at that.+  Conclusion: don't decompose [W] N s ~R N t, if there are any Given+  equalities that could later solve it. -Here is an example:+  But what does "any Given equalities that could later solve it" mean, precisely?+  It must be a Given constraint that could turn into N s ~ N t.  But that+  could include [G] (a b) ~ (c d), or even just [G] c.  But it'll definitely+  be an CIrredCan.  So we settle for having no CIrredCans at all, which is+  conservative but safe. See noGivenIrreds and #22331. +  Well not 100.0% safe. There could be a CDictCan with some un-expanded+  superclasses; but only in some very obscure recursive-superclass+  situations.++If there are no Irred Givens (which is quite common) then we will+successfuly decompose [W] (IO Age) ~R (IO Int), and solve it.  But+that won't happen and [W] (IO Age) ~R (IO Int) will be stuck.+We /could/, however, be a bit more aggressive about decomposition;+see Note [Decomposing newtypes a bit more aggressively].++Remember: decomposing Wanteds is always /sound/. This Note is+only about /completeness/.++Note [Decomposing newtypes a bit more aggressively]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+c.f. https://github.com/ghc-proposals/ghc-proposals/pull/549,+issue #22441, and discussion on !9282.++Consider [G] c, [W] (IO Int) ~R (IO Age)+where IO is abstract, and+   newtype Age = MkAge Int   -- Not abstract+With the above rules, if there any Given Irreds,+the Wanted is insoluble because we can't decompose it.  But in fact,+if we look at the defn of IO, roughly,+    newtype IO a = State# -> (State#, a)+we can see that decomposing [W] (IO Int) ~R (IO Age) to+    [W] Int ~R Age+definitely does not lose completeness. Why not? Because the role of+IO's argment is representational.  Hence:++  DecomposeNewtypeIdea:+     decompose [W] (N s1 .. sn) ~R (N t1 .. tn)+     if the roles of all N's arguments are representational++If N's arguments really /are/ representational this will not lose+completeness.  Here "really are representational" means "if you expand+all newtypes in N's RHS, we'd infer a representational role for each+of N's type variables in that expansion".  See Note [Role inference]+in GHC.Tc.TyCl.Utils.++But the user might /override/ a phantom role with an explicit role+annotation, and then we could (obscurely) get incompleteness.+Consider++   module A( silly, T ) where+     newtype T a = MkT Int+     type role T representational  -- Override phantom role++     silly :: Coercion (T Int) (T Bool)+     silly = Coercion  -- Typechecks by unwrapping the newtype++     data Coercion a b where  -- Actually defined in Data.Type.Coercion+       Coercion :: Coercible a b => Coercion a b++   module B where+     import A+     f :: T Int -> T Bool+     f = case silly of Coercion -> coerce++Here the `coerce` gives [W] (T Int) ~R (T Bool) which, if we decompose,+we'll get stuck with (Int ~R Bool).  Instead we want to use the+[G] (T Int) ~R (T Bool), which will be in the Irreds.++Summary: we could adopt (DecomposeNewtypeIdea), at the cost of a very+obscure incompleteness (above).  But no one is reporting a problem from+the lack of decompostion, so we'll just leave it for now.  This long+Note is just to record the thinking for our future selves.++Note [Decomposing AppTy equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For AppTy all the same questions arise as in+Note [Decomposing TyConApp equalities]. We have++    s1 ~r s2,  t1 ~N t2   ==>   s1 t1 ~r s2 t2       (rule CO_APP)+    s1 t1 ~N s2 t2        ==>   s1 ~N s2,  t1 ~N t2  (CO_LEFT, CO_RIGHT)++In the first of these, why do we need Nominal equality in (t1 ~N t2)?+See {2} below.++For sound and complete solving, we need both directions to decompose. So:+* At nominal role, all is well: we have both directions.+* At representational role, decomposition of Givens is unsound (see {1} below),+  and decomposition of Wanteds is incomplete.++Here is an example of the incompleteness for Wanteds:+     [G] g1 :: a ~R b     [W] w1 :: Maybe b ~R alpha a-    [W] w2 :: alpha ~ Maybe+    [W] w2 :: alpha ~N Maybe -Suppose we see w1 before w2. If we were to decompose, we would decompose-this to become+Suppose we see w1 before w2. If we decompose, using AppCo to prove w1, we get +    w1 := AppCo w3 w4     [W] w3 :: Maybe ~R alpha-    [W] w4 :: b ~ a+    [W] w4 :: b ~N a  Note that w4 is *nominal*. A nominal role here is necessary because AppCo-requires a nominal role on its second argument. (See (2) for an example of-why.) If we decomposed w1 to w3,w4, we would then get stuck, because w4-is insoluble. On the other hand, if we see w2 first, setting alpha := Maybe,-all is well, as we can decompose Maybe b ~R Maybe a into b ~R a.+requires a nominal role on its second argument. (See {2} for an example of+why.) Now we are stuck, because w4 is insoluble. On the other hand, if we+see w2 first, setting alpha := Maybe, all is well, as we can decompose+Maybe b ~R Maybe a into b ~R a.  Another example:-     newtype Phant x = MkPhant Int-     [W] w1 :: Phant Int ~R alpha Bool     [W] w2 :: alpha ~ Phant  If we see w1 first, decomposing would be disastrous, as we would then try to solve Int ~ Bool. Instead, spotting w2 allows us to simplify w1 to become-     [W] w1' :: Phant Int ~R Phant Bool  which can then (assuming MkPhant is in scope) be simplified to Int ~R Int, and all will be well. See also Note [Unwrap newtypes first]. -Bottom line: never decompose AppTy with representational roles.+Bottom line:+* Always decompose AppTy at nominal role: can_eq_app+* Never decompose AppTy at representational role (neither Given nor Wanted):+  the lack of an equation in can_eq_nc' -(1) Decomposing a Given AppTy over a representational role is simply-unsound. For example, if we have co1 :: Phant Int ~R a Bool (for-the newtype Phant, above), then we surely don't want any relationship-between Int and Bool, lest we also have co2 :: Phant ~ a around.+Extra points+{1}  Decomposing a Given AppTy over a representational role is simply+     unsound. For example, if we have co1 :: Phant Int ~R a Bool (for+     the newtype Phant, above), then we surely don't want any relationship+     between Int and Bool, lest we also have co2 :: Phant ~ a around. -(2) The role on the AppCo coercion is a conservative choice, because we don't-know the role signature of the function. For example, let's assume we could-have a representational role on the second argument of AppCo. Then, consider+{2} The role on the AppCo coercion is a conservative choice, because we don't+    know the role signature of the function. For example, let's assume we could+    have a representational role on the second argument of AppCo. Then, consider      data G a where    -- G will have a nominal role, as G is a GADT       MkG :: G Int@@ -1876,15 +1937,14 @@     co2 :: Age ~R Int    -- by newtype axiom     co3 = AppCo co1 co2 :: G Age ~R a Int    -- by our broken AppCo -and now co3 can be used to cast MkG to have type G Age, in violation of-the way GADTs are supposed to work (which is to use nominal equality).-+    and now co3 can be used to cast MkG to have type G Age, in violation of+    the way GADTs are supposed to work (which is to use nominal equality). -}  canDecomposableTyConAppOK :: CtEvidence -> EqRel                           -> TyCon -> [TcType] -> [TcType]                           -> TcS (StopOrContinue Ct)--- Precondition: tys1 and tys2 are the same length, hence "OK"+-- Precondition: tys1 and tys2 are the same finite length, hence "OK" canDecomposableTyConAppOK ev eq_rel tc tys1 tys2   = assert (tys1 `equalLength` tys2) $     do { traceTcS "canDecomposableTyConAppOK"@@ -1892,16 +1952,19 @@        ; case ev of            CtWanted { ctev_dest = dest, ctev_rewriters = rewriters }                   -- new_locs and tc_roles are both infinite, so-                  -- we are guaranteed that cos has the same length+                  -- we are guaranteed that cos has the same lengthm                   -- as tys1 and tys2-             -> do { cos <- zipWith4M (unifyWanted rewriters) new_locs tc_roles tys1 tys2+                  -- See Note [Fast path when decomposing TyConApps]+                  -- Caution: unifyWanteds is order sensitive+                  -- See Note [Decomposing Dependent TyCons and Processing Wanted Equalities]+             -> do { cos <- unifyWanteds rewriters new_locs tc_roles tys1 tys2                    ; setWantedEq dest (mkTyConAppCo role tc cos) }             CtGiven { ctev_evar = evar }              -> do { let ev_co = mkCoVarCo evar                    ; given_evs <- newGivenEvVars loc $                                   [ ( mkPrimEqPredRole r ty1 ty2-                                    , evCoercion $ mkNthCo r i ev_co )+                                    , evCoercion $ mkSelCo (SelTyCon i r) ev_co )                                   | (r, ty1, ty2, i) <- zip4 tc_roles tys1 tys2 [0..]                                   , r /= Phantom                                   , not (isCoercionTy ty1) && not (isCoercionTy ty2) ]@@ -1910,11 +1973,11 @@     ; stopWith ev "Decomposed TyConApp" }    where-    loc        = ctEvLoc ev-    role       = eqRelRole eq_rel+    loc  = ctEvLoc ev+    role = eqRelRole eq_rel -      -- infinite, as tyConRolesX returns an infinite tail of Nominal-    tc_roles   = tyConRolesX role tc+    -- Infinite, to allow for over-saturated TyConApps+    tc_roles = tyConRoleListX role tc        -- Add nuances to the location during decomposition:       --  * if the argument is a kind argument, remember this, so that error@@ -1936,6 +1999,38 @@                               = new_loc0 ]                ++ repeat loc +canDecomposableFunTy :: CtEvidence -> EqRel -> FunTyFlag+                     -> (Type,Type,Type)   -- (multiplicity,arg,res)+                     -> (Type,Type,Type)   -- (multiplicity,arg,res)+                     -> TcS (StopOrContinue Ct)+canDecomposableFunTy ev eq_rel af f1@(m1,a1,r1) f2@(m2,a2,r2)+  = do { traceTcS "canDecomposableFunTy"+                  (ppr ev $$ ppr eq_rel $$ ppr f1 $$ ppr f2)+       ; case ev of+           CtWanted { ctev_dest = dest, ctev_rewriters = rewriters }+             -> do { mult <- unifyWanted rewriters mult_loc (funRole role SelMult) m1 m2+                   ; arg  <- unifyWanted rewriters loc      (funRole role SelArg)  a1 a2+                   ; res  <- unifyWanted rewriters loc      (funRole role SelRes)  r1 r2+                   ; setWantedEq dest (mkNakedFunCo1 role af mult arg res) }++           CtGiven { ctev_evar = evar }+             -> do { let ev_co = mkCoVarCo evar+                   ; given_evs <- newGivenEvVars loc $+                                  [ ( mkPrimEqPredRole role' ty1 ty2+                                    , evCoercion $ mkSelCo (SelFun fs) ev_co )+                                  | (fs, ty1, ty2) <- [(SelMult, m1, m2)+                                                      ,(SelArg,  a1, a2)+                                                      ,(SelRes,  r1, r2)]+                                  , let role' = funRole role fs ]+                   ; emitWorkNC given_evs }++    ; stopWith ev "Decomposed TyConApp" }++  where+    loc      = ctEvLoc ev+    role     = eqRelRole eq_rel+    mult_loc = updateCtLocOrigin loc toInvisibleOrigin+ -- | Call when canonicalizing an equality fails, but if the equality is -- representational, there is some hope for the future. -- Examples in Note [Use canEqFailure in canDecomposableTyConApp]@@ -1966,19 +2061,6 @@        ; continueWith (mkIrredCt ShapeMismatchReason new_ev) }  {--Note [Decomposing TyConApps]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~-If we see (T s1 t1 ~ T s2 t2), then we can just decompose to-  (s1 ~ s2, t1 ~ t2)-and push those back into the work list.  But if-  s1 = K k1    s2 = K k2-then we will just decompose s1~s2, and it might be better to-do so on the spot.  An important special case is where s1=s2,-and we get just Refl.--So canDecomposableTyCon is a fast-path decomposition that uses-unifyWanted etc to short-cut that work.- Note [Canonicalising type applications] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Given (s1 t1) ~ ty2, how should we proceed?@@ -2106,8 +2188,37 @@    where     k1 = canEqLHSKind lhs1-    k2 = tcTypeKind xi2+    k2 = typeKind xi2 ++{-+Note [Kind Equality Orientation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+While in theory [W] x ~ y and [W] y ~ x ought to give us the same behaviour, in practice it does not.+See Note [Fundeps with instances, and equality orientation] where this is discussed at length.+As a rule of thumb: we keep the newest unification variables on the left of the equality.+See also Note [Improvement orientation] in GHC.Tc.Solver.Interact.++In particular, `canEqCanLHSHetero` produces the following constraint equalities++[X] (xi1 :: ki1) ~ (xi2 :: ki2)+  -->  [X] kco :: ki1 ~ ki2+       [X] co : xi1 :: ki1 ~ (xi2 |> sym kco) :: ki1++Note that the types in the LHS of the new constraints are the ones that were on the LHS of+the original constraint.++--- Historical note ---+We prevously used to flip the kco to avoid using a sym in the cast++[X] (xi1 :: ki1) ~ (xi2 :: ki2)+  -->  [X] kco :: ki2 ~ ki1+       [X] co : xi1 :: ki1 ~ (xi2 |> kco) :: ki1++But this sent solver in an infinite loop (see #19415).+-- End of historical note --+-}+ canEqCanLHSHetero :: CtEvidence         -- :: (xi1 :: ki1) ~ (xi2 :: ki2)                   -> EqRel -> SwapFlag                   -> CanEqLHS           -- xi1@@ -2117,48 +2228,52 @@                   -> TcS (StopOrContinue Ct) canEqCanLHSHetero ev eq_rel swapped lhs1 ki1 xi2 ki2   -- See Note [Equalities with incompatible kinds]-  = do { (kind_ev, kind_co) <- mk_kind_eq   -- :: ki2 ~N ki1+  -- See Note [Kind Equality Orientation]+  -- NB: preserve left-to-right orientation!!+  -- See Note [Fundeps with instances, and equality orientation]+  --     wrinkle (W2) in GHC.Tc.Solver.Interact+  = do { (kind_ev, kind_co) <- mk_kind_eq   -- :: ki1 ~N ki2 -       ; let  -- kind_co :: (ki2 :: *) ~N (ki1 :: *)   (whether swapped or not)+       ; let  -- kind_co :: (ki1 :: *) ~N (ki2 :: *)   (whether swapped or not)              lhs_redn = mkReflRedn role xi1-             rhs_redn = mkGReflRightRedn role xi2 kind_co+             rhs_redn = mkGReflRightRedn role xi2 (mkSymCo kind_co)               -- See Note [Equalities with incompatible kinds], Wrinkle (1)              -- This will be ignored in rewriteEqEvidence if the work item is a Given              rewriters = rewriterSetFromCo kind_co         ; traceTcS "Hetero equality gives rise to kind equality"-           (ppr kind_co <+> dcolon <+> sep [ ppr ki2, text "~#", ppr ki1 ])+           (ppr kind_co <+> dcolon <+> sep [ ppr ki1, text "~#", ppr ki2 ])        ; type_ev <- rewriteEqEvidence rewriters ev swapped lhs_redn rhs_redn         ; emitWorkNC [type_ev]  -- delay the type equality until after we've finished                                -- the kind equality, which may unlock things                                -- See Note [Equalities with incompatible kinds] -       ; canEqNC kind_ev NomEq ki2 ki1 }+       ; canEqNC kind_ev NomEq ki1 ki2 }   where     mk_kind_eq :: TcS (CtEvidence, CoercionN)     mk_kind_eq = case ev of       CtGiven { ctev_evar = evar }-        -> do { let kind_co = maybe_sym $ mkTcKindCo (mkTcCoVarCo evar)  -- :: k2 ~ k1+        -> do { let kind_co = maybe_sym $ mkKindCo (mkCoVarCo evar) -- :: k1 ~ k2               ; kind_ev <- newGivenEvVar kind_loc (kind_pty, evCoercion kind_co)               ; return (kind_ev, ctEvCoercion kind_ev) }        CtWanted { ctev_rewriters = rewriters }-        -> newWantedEq kind_loc rewriters Nominal ki2 ki1+        -> newWantedEq kind_loc rewriters Nominal ki1 ki2      xi1      = canEqLHSType lhs1     loc      = ctev_loc ev     role     = eqRelRole eq_rel     kind_loc = mkKindLoc xi1 xi2 loc-    kind_pty = mkHeteroPrimEqPred liftedTypeKind liftedTypeKind ki2 ki1+    kind_pty = mkHeteroPrimEqPred liftedTypeKind liftedTypeKind ki1 ki2      maybe_sym = case swapped of-          IsSwapped  -> id         -- if the input is swapped, then we already-                                   -- will have k2 ~ k1-          NotSwapped -> mkTcSymCo+          IsSwapped  -> mkSymCo         -- if the input is swapped, then we+                                        -- will have k2 ~ k1, so flip it to k1 ~ k2+          NotSwapped -> id --- guaranteed that tcTypeKind lhs == tcTypeKind rhs+-- guaranteed that typeKind lhs == typeKind rhs canEqCanLHSHomo :: CtEvidence                 -> EqRel -> SwapFlag                 -> CanEqLHS           -- lhs (or, if swapped, rhs)@@ -2168,7 +2283,7 @@ canEqCanLHSHomo ev eq_rel swapped lhs1 ps_xi1 xi2 ps_xi2   | (xi2', mco) <- split_cast_ty xi2   , Just lhs2 <- canEqLHS_maybe xi2'-  = canEqCanLHS2 ev eq_rel swapped lhs1 ps_xi1 lhs2 (ps_xi2 `mkCastTyMCo` mkTcSymMCo mco) mco+  = canEqCanLHS2 ev eq_rel swapped lhs1 ps_xi1 lhs2 (ps_xi2 `mkCastTyMCo` mkSymMCo mco) mco    | otherwise   = canEqCanLHSFinish ev eq_rel swapped lhs1 ps_xi2@@ -2213,6 +2328,7 @@    | TyFamLHS fun_tc1 fun_args1 <- lhs1   , TyFamLHS fun_tc2 fun_args2 <- lhs2+  -- See Note [Decomposing type family applications]   = do { traceTcS "canEqCanLHS2 two type families" (ppr lhs1 $$ ppr lhs2)           -- emit wanted equalities for injective type families@@ -2285,7 +2401,7 @@   = finish_without_swapping    where-    sym_mco = mkTcSymMCo mco+    sym_mco = mkSymMCo mco      do_swap = rewriteCastedEquality ev eq_rel swapped (canEqLHSType lhs1) (canEqLHSType lhs2) mco     finish_without_swapping = canEqCanLHSFinish ev eq_rel swapped lhs1 (ps_xi2 `mkCastTyMCo` mco)@@ -2324,7 +2440,7 @@                                   (TyFamLHS fun_tc2 fun_args2)                                   (ps_xi1 `mkCastTyMCo` sym_mco) } }   where-    sym_mco = mkTcSymMCo mco+    sym_mco = mkSymMCo mco     rhs = ps_xi2 `mkCastTyMCo` mco  -- The RHS here is either not CanEqLHS, or it's one that we@@ -2347,7 +2463,7 @@                                      (mkReflRedn role rhs)       -- by now, (TyEq:K) is already satisfied-       ; massert (canEqLHSKind lhs `eqType` tcTypeKind rhs)+       ; massert (canEqLHSKind lhs `eqType` typeKind rhs)       -- by now, (TyEq:N) is already satisfied (if applicable)        ; assertPprM ty_eq_N_OK $@@ -2433,7 +2549,7 @@                -> TcS (StopOrContinue Ct)   -- always Stop canEqReflexive ev eq_rel ty   = do { setEvBindIfWanted ev (evCoercion $-                               mkTcReflCo (eqRelRole eq_rel) ty)+                               mkReflCo (eqRelRole eq_rel) ty)        ; stopWith ev "Solved by reflexivity" }  rewriteCastedEquality :: CtEvidence     -- :: lhs ~ (rhs |> mco), or (rhs |> mco) ~ lhs@@ -2449,7 +2565,7 @@     lhs_redn = mkGReflRightMRedn role lhs sym_mco     rhs_redn = mkGReflLeftMRedn  role rhs mco -    sym_mco = mkTcSymMCo mco+    sym_mco = mkSymMCo mco     role    = eqRelRole eq_rel  {- Note [Equalities with incompatible kinds]@@ -2465,8 +2581,8 @@  (where [X] is [G] or [W]), we go to -  [X] co :: k2 ~ k1-  [X] (tv :: k1) ~ ((rhs |> co) :: k1)+  [X] co :: k1 ~ k2+  [X] (tv :: k1) ~ ((rhs |> sym co) :: k1)  We carry on with the *kind equality*, not the type equality, because solving the former may unlock the latter. This choice is made in@@ -2479,7 +2595,7 @@      for the type-level one. See Note [Wanteds rewrite Wanteds] in GHC.Tc.Types.Constraint.      This is done in canEqCanLHSHetero. - (2) If we have [W] w :: alpha ~ (rhs |> co_hole), should we unify alpha? No.+ (2) If we have [W] w :: alpha ~ (rhs |> sym co_hole), should we unify alpha? No.      The problem is that the wanted w is effectively rewritten by another wanted,      and unifying alpha effectively promotes this wanted to a given. Doing so      means we lose track of the rewriter set associated with the wanted.@@ -2497,8 +2613,8 @@      unifyTest in canEqTyVarFunEq.   (3) Suppose we have [W] (a :: k1) ~ (rhs :: k2). We duly follow the-     algorithm detailed here, producing [W] co :: k2 ~ k1, and adding-     [W] (a :: k1) ~ ((rhs |> co) :: k1) to the irreducibles. Some time+     algorithm detailed here, producing [W] co :: k1 ~ k2, and adding+     [W] (a :: k1) ~ ((rhs |> sym co) :: k1) to the irreducibles. Some time      later, we solve co, and fill in co's coercion hole. This kicks out      the irreducible as described in (2).      But now, during canonicalization, we see the cast@@ -2986,7 +3102,7 @@   rewriteEvidence rewriters old_ev (Reduction co new_pred)-  | isTcReflCo co -- See Note [Rewriting with Refl]+  | isReflCo co -- See Note [Rewriting with Refl]   = assert (isEmptyRewriterSet rewriters) $     continueWith (setCtEvPredType old_ev new_pred) @@ -2998,7 +3114,7 @@   where     -- mkEvCast optimises ReflCo     new_tm = mkEvCast (evId old_evar)-                (tcDowngradeRole Representational (ctEvRole ev) co)+                (downgradeRole Representational (ctEvRole ev) co)  rewriteEvidence new_rewriters                 ev@(CtWanted { ctev_dest = dest@@ -3006,10 +3122,10 @@                              , ctev_rewriters = rewriters })                 (Reduction co new_pred)   = do { mb_new_ev <- newWanted loc rewriters' new_pred-       ; massert (tcCoercionRole co == ctEvRole ev)+       ; massert (coercionRole co == ctEvRole ev)        ; setWantedEvTerm dest             (mkEvCast (getEvExpr mb_new_ev)-                      (tcDowngradeRole Representational (ctEvRole ev) (mkSymCo co)))+                      (downgradeRole Representational (ctEvRole ev) (mkSymCo co)))        ; case mb_new_ev of             Fresh  new_ev -> continueWith new_ev             Cached _      -> stopWith ev "Cached wanted" }@@ -3043,14 +3159,14 @@ -- It's all a form of rewriteEvidence, specialised for equalities rewriteEqEvidence new_rewriters old_ev swapped (Reduction lhs_co nlhs) (Reduction rhs_co nrhs)   | NotSwapped <- swapped-  , isTcReflCo lhs_co      -- See Note [Rewriting with Refl]-  , isTcReflCo rhs_co+  , isReflCo lhs_co      -- See Note [Rewriting with Refl]+  , isReflCo rhs_co   = return (setCtEvPredType old_ev new_pred)    | CtGiven { ctev_evar = old_evar } <- old_ev-  = do { let new_tm = evCoercion ( mkTcSymCo lhs_co-                                  `mkTcTransCo` maybeTcSymCo swapped (mkTcCoVarCo old_evar)-                                  `mkTcTransCo` rhs_co)+  = do { let new_tm = evCoercion ( mkSymCo lhs_co+                                  `mkTransCo` maybeSymCo swapped (mkCoVarCo old_evar)+                                  `mkTransCo` rhs_co)        ; newGivenEvVar loc' (new_pred, new_tm) }    | CtWanted { ctev_dest = dest@@ -3058,10 +3174,10 @@   , let rewriters' = rewriters S.<> new_rewriters   = do { (new_ev, hole_co) <- newWantedEq loc' rewriters'                                           (ctEvRole old_ev) nlhs nrhs-       ; let co = maybeTcSymCo swapped $+       ; let co = maybeSymCo swapped $                   lhs_co                   `mkTransCo` hole_co-                  `mkTransCo` mkTcSymCo rhs_co+                  `mkTransCo` mkSymCo rhs_co        ; setWantedEq dest co        ; traceTcS "rewriteEqEvidence" (vcat [ ppr old_ev                                             , ppr nlhs@@ -3110,25 +3226,27 @@ -- See Note [unifyWanted] -- The returned coercion's role matches the input parameter unifyWanted rewriters loc Phantom ty1 ty2-  = do { kind_co <- unifyWanted rewriters loc Nominal (tcTypeKind ty1) (tcTypeKind ty2)+  = do { kind_co <- unifyWanted rewriters loc Nominal (typeKind ty1) (typeKind ty2)        ; return (mkPhantomCo kind_co ty1 ty2) }  unifyWanted rewriters loc role orig_ty1 orig_ty2   = go orig_ty1 orig_ty2   where-    go ty1 ty2 | Just ty1' <- tcView ty1 = go ty1' ty2-    go ty1 ty2 | Just ty2' <- tcView ty2 = go ty1 ty2'+    go ty1 ty2 | Just ty1' <- coreView ty1 = go ty1' ty2+    go ty1 ty2 | Just ty2' <- coreView ty2 = go ty1 ty2' -    go (FunTy _ w1 s1 t1) (FunTy _ w2 s2 t2)+    go (FunTy af1 w1 s1 t1) (FunTy af2 w2 s2 t2)+      | af1 == af2    -- Important!  See #21530       = do { co_s <- unifyWanted rewriters loc role s1 s2            ; co_t <- unifyWanted rewriters loc role t1 t2            ; co_w <- unifyWanted rewriters loc Nominal w1 w2-           ; return (mkFunCo role co_w co_s co_t) }+           ; return (mkNakedFunCo1 role af1 co_w co_s co_t) }+     go (TyConApp tc1 tys1) (TyConApp tc2 tys2)       | tc1 == tc2, tys1 `equalLength` tys2       , isInjectiveTyCon tc1 role -- don't look under newtypes at Rep equality       = do { cos <- zipWith3M (unifyWanted rewriters loc)-                              (tyConRolesX role tc1) tys1 tys2+                              (tyConRoleListX role tc1) tys1 tys2            ; return (mkTyConAppCo role tc1 cos) }      go ty1@(TyVarTy tv) ty2@@ -3148,6 +3266,58 @@     go ty1 ty2 = bale_out ty1 ty2      bale_out ty1 ty2-       | ty1 `tcEqType` ty2 = return (mkTcReflCo role ty1)+       | ty1 `tcEqType` ty2 = return (mkReflCo role ty1)         -- Check for equality; e.g. a ~ a, or (m a) ~ (m a)        | otherwise = emitNewWantedEq loc rewriters role orig_ty1 orig_ty2+++{-+Note [Decomposing Dependent TyCons and Processing Wanted Equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we decompose a dependent tycon we obtain a list of+mixed wanted type and kind equalities. Ideally we want+all the kind equalities to get solved first so that we avoid+generating duplicate kind equalities++For example, consider decomposing a TyCon equality++    (0) [W] T k_fresh (t1::k_fresh) ~ T k1 (t2::k_fresh)++This gives rise to 2 equalities in the solver worklist++    (1) [W] k_fresh ~ k1+    (2) [W] t1::k_fresh ~ t2::k1++The solver worklist is processed in LIFO order:+see GHC.Tc.Solver.InertSet.selectWorkItem.+i.e. (2) is processed _before_ (1). Now, while solving (2)+we would call `canEqCanLHSHetero` and that would emit a+wanted kind equality++    (3) [W] k_fresh ~ k1++But (3) is exactly the same as (1)!++To avoid such duplicate wanted constraints from being added to the worklist,+we ensure that (2) is processed before (1). Since we are processing+the worklist in a LIFO ordering, we do it by emitting (1) before (2).+This is exactly what we do in `unifyWanteds`.++NB: This ordering is not needed when we decompose FunTyCons as they are not dependently typed+-}++-- NB: Length of [CtLoc] and [Roles] may be infinite+-- but list of RHS [TcType] and LHS [TcType] is finite and both are of equal length+unifyWanteds :: RewriterSet -> [CtLoc] -> [Role]+             -> [TcType] -- List of RHS types+             -> [TcType] -- List of LHS types+             -> TcS [Coercion]+unifyWanteds rewriters ctlocs roles rhss lhss = unify_wanteds rewriters $ zip4 ctlocs roles rhss lhss+  where+    -- Order is important here+    -- See Note [Decomposing Dependent TyCons and Processing Wanted Equalities]+    unify_wanteds _ [] = return []+    unify_wanteds rewriters ((new_loc, tc_role, ty1, ty2) : rest)+       = do { cos <- unify_wanteds rewriters rest+            ; co  <- unifyWanted rewriters new_loc tc_role ty1 ty2+            ; return (co:cos) }
compiler/GHC/Tc/Solver/Interact.hs view
@@ -1,4 +1,3 @@-{-# OPTIONS_GHC -Wno-incomplete-record-updates #-} {-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}  module GHC.Tc.Solver.Interact (@@ -11,21 +10,14 @@                          infinity, IntWithInf, intGtLimit ) import GHC.Tc.Solver.Canonical import GHC.Types.Var.Set-import GHC.Core.Type as Type-import GHC.Core.InstEnv         ( DFunInstType )  import GHC.Types.Var import GHC.Tc.Errors.Types import GHC.Tc.Utils.TcType import GHC.Builtin.Names ( coercibleTyConKey, heqTyConKey, eqTyConKey, ipClassKey )-import GHC.Core.Coercion.Axiom ( CoAxBranch (..), CoAxiom (..), TypeEqn, fromBranches, sfInteractInert, sfInteractTop )-import GHC.Core.Class-import GHC.Core.TyCon import GHC.Tc.Instance.FunDeps import GHC.Tc.Instance.Family import GHC.Tc.Instance.Class ( InstanceWhat(..), safeOverlap )-import GHC.Core.FamInstEnv-import GHC.Core.Unify ( tcUnifyTyWithTFs, ruleMatchTyKiX )  import GHC.Tc.Types.Evidence import GHC.Utils.Outputable@@ -33,32 +25,46 @@  import GHC.Tc.Types import GHC.Tc.Types.Constraint-import GHC.Core.Predicate import GHC.Tc.Types.Origin import GHC.Tc.Utils.TcMType( promoteMetaTyVarTo ) import GHC.Tc.Solver.Types import GHC.Tc.Solver.InertSet import GHC.Tc.Solver.Monad-import GHC.Data.Bag-import GHC.Utils.Monad ( concatMapM, foldlM )  import GHC.Core-import Data.List( deleteFirstsBy )-import Data.Function ( on )+import GHC.Core.Type as Type+import GHC.Core.InstEnv     ( DFunInstType )+import GHC.Core.Class+import GHC.Core.TyCon+import GHC.Core.Predicate+import GHC.Core.Coercion+import GHC.Core.FamInstEnv+import GHC.Core.Unify ( tcUnifyTyWithTFs, ruleMatchTyKiX )+import GHC.Core.Coercion.Axiom ( CoAxBranch (..), CoAxiom (..), TypeEqn, fromBranches+                               , sfInteractInert, sfInteractTop )+ import GHC.Types.SrcLoc import GHC.Types.Var.Env+import GHC.Types.Unique( hasKey ) -import qualified Data.Semigroup as S-import Control.Monad-import Data.Maybe ( listToMaybe, mapMaybe )+import GHC.Data.Bag import GHC.Data.Pair (Pair(..))-import GHC.Types.Unique( hasKey )-import GHC.Driver.Session++import GHC.Utils.Monad ( concatMapM, foldlM ) import GHC.Utils.Misc++import GHC.Driver.Session+ import qualified GHC.LanguageExtensions as LangExt +import Data.List( deleteFirstsBy )+import Data.Maybe ( listToMaybe, mapMaybe )+import Data.Function ( on )+import qualified Data.Semigroup as S+ import Control.Monad.Trans.Class import Control.Monad.Trans.Maybe+import Control.Monad  {- **********************************************************************@@ -442,8 +448,8 @@   ppr KeepInert = text "keep inert"   ppr KeepWork  = text "keep work-item" -solveOneFromTheOther :: CtEvidence  -- Inert    (Dict or Irred)-                     -> CtEvidence  -- WorkItem (same predicate as inert)+solveOneFromTheOther :: Ct  -- Inert    (Dict or Irred)+                     -> Ct  -- WorkItem (same predicate as inert)                      -> TcS InteractResult -- Precondition: -- * inert and work item represent evidence for the /same/ predicate@@ -453,24 +459,41 @@ -- although we don't rewrite wanteds with wanteds, we can combine -- two wanteds into one by solving one from the other -solveOneFromTheOther ev_i ev_w+solveOneFromTheOther ct_i ct_w   | CtWanted { ctev_loc = loc_w } <- ev_w   , prohibitedSuperClassSolve loc_i loc_w-  = -- inert must be Given+  = -- Inert must be Given     do { traceTcS "prohibitedClassSolve1" (ppr ev_i $$ ppr ev_w)        ; return KeepWork }    | CtWanted {} <- ev_w-       -- Inert is Given or Wanted-  = return $ case ev_i of-               CtWanted {} -> choose_better_loc-                 -- both are Wanted; choice of which to keep is-                 -- arbitrary. So we look at the context to choose-                 -- which would make a better error message+  = -- Inert is Given or Wanted+    case ev_i of+      CtGiven {} -> return KeepInert+        -- work is Wanted; inert is Given: easy choice. -               _           -> KeepInert-                 -- work is Wanted; inert is Given: easy choice.+      CtWanted {} -- Both are Wanted+        -- If only one has no pending superclasses, use it+        -- Otherwise we can get infinite superclass expansion (#22516)+        -- in silly cases like   class C T b => C a b where ...+        | not is_psc_i, is_psc_w     -> return KeepInert+        | is_psc_i,     not is_psc_w -> return KeepWork +        -- If only one is a WantedSuperclassOrigin (arising from expanding+        -- a Wanted class constraint), keep the other: wanted superclasses+        -- may be unexpected by users+        | not is_wsc_orig_i, is_wsc_orig_w     -> return KeepInert+        | is_wsc_orig_i,     not is_wsc_orig_w -> return KeepWork++        -- otherwise, just choose the lower span+        -- reason: if we have something like (abs 1) (where the+        -- Num constraint cannot be satisfied), it's better to+        -- get an error about abs than about 1.+        -- This test might become more elaborate if we see an+        -- opportunity to improve the error messages+        | ((<) `on` ctLocSpan) loc_i loc_w -> return KeepInert+        | otherwise                        -> return KeepWork+   -- From here on the work-item is Given    | CtWanted { ctev_loc = loc_i } <- ev_i@@ -492,31 +515,21 @@   | otherwise   -- Both are Given, levels differ   = return different_level_strategy   where+     ev_i  = ctEvidence ct_i+     ev_w  = ctEvidence ct_w+      pred  = ctEvPred ev_i+      loc_i = ctEvLoc ev_i      loc_w = ctEvLoc ev_w      lvl_i = ctLocLevel loc_i      lvl_w = ctLocLevel loc_w -     choose_better_loc-       -- if only one is a WantedSuperclassOrigin (arising from expanding-       -- a Wanted class constraint), keep the other: wanted superclasses-       -- may be unexpected by users-       | is_wanted_superclass_loc loc_i-       , not (is_wanted_superclass_loc loc_w) = KeepWork--       | not (is_wanted_superclass_loc loc_i)-       , is_wanted_superclass_loc loc_w = KeepInert--        -- otherwise, just choose the lower span-        -- reason: if we have something like (abs 1) (where the-        -- Num constraint cannot be satisfied), it's better to-        -- get an error about abs than about 1.-        -- This test might become more elaborate if we see an-        -- opportunity to improve the error messages-       | ((<) `on` ctLocSpan) loc_i loc_w = KeepInert-       | otherwise                        = KeepWork+     is_psc_w = isPendingScDict ct_w+     is_psc_i = isPendingScDict ct_i +     is_wsc_orig_i = is_wanted_superclass_loc loc_i+     is_wsc_orig_w = is_wanted_superclass_loc loc_w      is_wanted_superclass_loc = isWantedSuperclassOrigin . ctLocOrigin       different_level_strategy  -- Both Given@@ -644,35 +657,35 @@ -- mean that (ty1 ~ ty2) interactIrred :: InertCans -> Ct -> TcS (StopOrContinue Ct) -interactIrred inerts workItem@(CIrredCan { cc_ev = ev_w, cc_reason = reason })+interactIrred inerts ct_w@(CIrredCan { cc_ev = ev_w, cc_reason = reason })   | isInsolubleReason reason                -- For insolubles, don't allow the constraint to be dropped                -- which can happen with solveOneFromTheOther, so that                -- we get distinct error messages with -fdefer-type-errors-  = continueWith workItem+  = continueWith ct_w    | let (matching_irreds, others) = findMatchingIrreds (inert_irreds inerts) ev_w   , ((ct_i, swap) : _rest) <- bagToList matching_irreds         -- See Note [Multiple matching irreds]   , let ev_i = ctEvidence ct_i-  = do { what_next <- solveOneFromTheOther ev_i ev_w-       ; traceTcS "iteractIrred" (ppr workItem $$ ppr what_next $$ ppr ct_i)+  = do { what_next <- solveOneFromTheOther ct_i ct_w+       ; traceTcS "iteractIrred" (ppr ct_w $$ ppr what_next $$ ppr ct_i)        ; case what_next of             KeepInert -> do { setEvBindIfWanted ev_w (swap_me swap ev_i)                             ; return (Stop ev_w (text "Irred equal" <+> parens (ppr what_next))) }             KeepWork ->  do { setEvBindIfWanted ev_i (swap_me swap ev_w)                             ; updInertIrreds (\_ -> others)-                            ; continueWith workItem } }+                            ; continueWith ct_w } }    | otherwise-  = continueWith workItem+  = continueWith ct_w    where     swap_me :: SwapFlag -> CtEvidence -> EvTerm     swap_me swap ev       = case swap of            NotSwapped -> ctEvTerm ev-           IsSwapped  -> evCoercion (mkTcSymCo (evTermCoercion (ctEvTerm ev)))+           IsSwapped  -> evCoercion (mkSymCo (evTermCoercion (ctEvTerm ev)))  interactIrred _ wi = pprPanic "interactIrred" (ppr wi) @@ -995,7 +1008,7 @@ -}  interactDict :: InertCans -> Ct -> TcS (StopOrContinue Ct)-interactDict inerts workItem@(CDictCan { cc_ev = ev_w, cc_class = cls, cc_tyargs = tys })+interactDict inerts ct_w@(CDictCan { cc_ev = ev_w, cc_class = cls, cc_tyargs = tys })   | Just ct_i <- lookupInertDict inerts (ctEvLoc ev_w) cls tys   , let ev_i = ctEvidence ct_i   = -- There is a matching dictionary in the inert set@@ -1009,22 +1022,22 @@      do { -- Ths short-cut solver didn't fire, so we          -- solve ev_w from the matching inert ev_i we found-         what_next <- solveOneFromTheOther ev_i ev_w+         what_next <- solveOneFromTheOther ct_i ct_w        ; traceTcS "lookupInertDict" (ppr what_next)        ; case what_next of            KeepInert -> do { setEvBindIfWanted ev_w (ctEvTerm ev_i)                            ; return $ Stop ev_w (text "Dict equal" <+> parens (ppr what_next)) }            KeepWork  -> do { setEvBindIfWanted ev_i (ctEvTerm ev_w)                            ; updInertDicts $ \ ds -> delDict ds cls tys-                           ; continueWith workItem } } }+                           ; continueWith ct_w } } }    | cls `hasKey` ipClassKey   , isGiven ev_w-  = interactGivenIP inerts workItem+  = interactGivenIP inerts ct_w    | otherwise   = do { addFunDepWork inerts ev_w cls-       ; continueWith workItem  }+       ; continueWith ct_w  }  interactDict _ wi = pprPanic "interactDict" (ppr wi) @@ -1385,7 +1398,7 @@ injectivity.  1. When we have a [W] F tys1 ~ F tys2. This is handled in canEqCanLHS2, and-described in Note [Decomposing equality] in GHC.Tc.Solver.Canonical.+described in Note [Decomposing type family applications] in GHC.Tc.Solver.Canonical.  2. When we have [W] F tys1 ~ T and [W] F tys2 ~ T. Note that neither of these constraints rewrites the other, as they have different LHSs. This is done@@ -1523,10 +1536,10 @@                                    , cc_eq_rel = eq_rel })   | Just (ev_i, swapped) <- inertsCanDischarge inerts workItem   = do { setEvBindIfWanted ev $-         evCoercion (maybeTcSymCo swapped $-                     tcDowngradeRole (eqRelRole eq_rel)-                                     (ctEvRole ev_i)-                                     (ctEvCoercion ev_i))+         evCoercion (maybeSymCo swapped $+                     downgradeRole (eqRelRole eq_rel)+                                   (ctEvRole ev_i)+                                   (ctEvCoercion ev_i))         ; stopWith ev "Solved from inert" } @@ -1588,10 +1601,10 @@        ; traceTcS "Sneaky unification:" $                        vcat [text "Unifies:" <+> ppr tv <+> text ":=" <+> ppr xi,                              text "Coercion:" <+> pprEq tv_ty xi,-                             text "Left Kind is:" <+> ppr (tcTypeKind tv_ty),-                             text "Right Kind is:" <+> ppr (tcTypeKind xi) ]+                             text "Left Kind is:" <+> ppr (typeKind tv_ty),+                             text "Right Kind is:" <+> ppr (typeKind xi) ]        ; unifyTyVar tv xi-       ; setEvBindIfWanted wd (evCoercion (mkTcNomReflCo xi))+       ; setEvBindIfWanted wd (evCoercion (mkNomReflCo xi))        ; n_kicked <- kickOutAfterUnification tv        ; return (Stop wd (text "Solved by unification" <+> pprKicked n_kicked)) } @@ -1726,8 +1739,12 @@ It's exactly the same with implicit parameters, except that the "aggressive" approach would be much easier to implement. -Note [Fundeps with instances]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Note [Fundeps with instances, and equality orientation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This Note describes a delicate interaction that constrains the orientation of+equalities. This one is about fundeps, but the /exact/ same thing arises for+type-family injectivity constraints: see Note [Improvement orientation].+ doTopFundepImprovement compares the constraint with all the instance declarations, to see if we can produce any equalities. E.g    class C2 a b | a -> b@@ -1741,53 +1758,123 @@     work_item: dwrk :: C (T @ka (a::ka)) (T @kb0 (b0::kb0)) Char       where kb0, b0 are unification vars-   ==> {fundeps against instance; k0, y0 fresh unification vars}-       [W] T kb0 (b0::kb0) ~ T k0 (y0::k0)-       Add dwrk to inert set-   ==> {solve that equality kb0 := k0, b0 := y0++   ==> {doTopFundepImprovement: compare work_item with instance,+        generate /fresh/ unification variables kfresh0, yfresh0,+        emit a new Wanted, and add dwrk to inert set}++   Suppose we emit this new Wanted from the fundep:+       [W] T kb0 (b0::kb0) ~ T kfresh0 (yfresh0::kfresh0)++   ==> {solve that equality kb0 := kfresh0, b0 := yfresh0}    Now kick out dwrk, since it mentions kb0    But now we are back to the start!  Loop! -NB1: this example relies on an instance that does not satisfy-the coverage condition (although it may satisfy the weak coverage-condition), which is known to lead to termination trouble+NB1: This example relies on an instance that does not satisfy the+     coverage condition (although it may satisfy the weak coverage+     condition), and hence whose fundeps generate fresh unification+     variables.  Not satisfying the coverage condition is known to+     lead to termination trouble, but in this case it's plain silly. -NB2: if the unification was the other way round, k0:=kb0, all would be-well.  It's a very delicate problem.+NB2: In this example, the third parameter to C ensures that the+     instance doesn't actually match the Wanted, so we can't use it to+     solve the Wanted -The ticket #19415 discusses various solutions, but the one we adopted-is very simple:+We solve the problem by (#21703): -* There is a flag in CDictCan (cc_fundeps :: Bool)+    carefully orienting the new Wanted so that all the+    freshly-generated unification variables are on the LHS. -* cc_fundeps = True means-    a) The class has fundeps-    b) We have not had a successful hit against instances yet+    Thus we emit+       [W] T kfresh0 (yfresh0::kfresh0) ~ T kb0 (b0::kb0)+    and /NOT/+       [W] T kb0 (b0::kb0) ~ T kfresh0 (yfresh0::kfresh0) -* In doTopFundepImprovement, if we emit some constraints we flip the flag-  to False, so that we won't try again with the same CDictCan.  In our-  example, dwrk will have its flag set to False.+Now we'll unify kfresh0:=kb0, yfresh0:=b0, and all is well.  The general idea+is that we want to preferentially eliminate those freshly-generated+unification variables, rather than unifying older variables, which causes+kick-out etc. -* Not that if we have no "hits" we must /not/ flip the flag. We might have-      dwrk :: C alpha beta Char-  which does not yet trigger fundeps from the instance, but later we-  get alpha := T ka a.  We could be cleverer, and spot that the constraint-  is such that we will /never/ get any hits (no unifiers) but we don't do-  that yet.+Keeping younger variables on the left also gives very minor improvement in+the compiler performance by having less kick-outs and allocations (-0.1% on+average).  Indeed Historical Note [Eliminate younger unification variables]+in GHC.Tc.Utils.Unify describes an earlier attempt to do so systematically,+apparently now in abeyance. -Easy!  What could go wrong?-* Maybe the class has multiple fundeps, and we get hit with one but not-  the other.  Per-fundep flags?-* Maybe we get a hit against one instance with one fundep but, after-  the work-item is instantiated a bit more, we get a second hit-  against a second instance.  (This is a pretty strange and-  undesirable thing anyway, and can only happen with overlapping-  instances; one example is in Note [Weird fundeps].)+But this is is a delicate solution. We must take care to /preserve/+orientation during solving. Wrinkles: -But both of these seem extremely exotic, and ignoring them threatens-completeness (fixable with some type signature), but not termination-(not fixable).  So for now we are just doing the simplest thing.+(W1) We start with+       [W] T kfresh0 (yfresh0::kfresh0) ~ T kb0 (b0::kb0)+     Decompose to+       [W] kfresh0 ~ kb0+       [W] (yfresh0::kfresh0) ~ (b0::kb0)+     Preserve orientiation when decomposing!! +(W2) Suppose we happen to tackle the second Wanted from (W1)+     first. Then in canEqCanLHSHetero we emit a /kind/ equality, as+     well as a now-homogeneous type equality+       [W] kco : kfresh0 ~ kb0+       [W] (yfresh0::kfresh0) ~ (b0::kb0) |> (sym kco)+     Preserve orientation in canEqCanLHSHetero!!  (Failing to+     preserve orientation here was the immediate cause of #21703.)++(W3) There is a potential interaction with the swapping done by+     GHC.Tc.Utils.Unify.swapOverTyVars.  We think it's fine, but it's+     a slight worry.  See especially Note [TyVar/TyVar orientation] in+     that module.++The trouble is that "preserving orientation" is a rather global invariant,+and sometimes we definitely do want to swap (e.g. Int ~ alpha), so we don't+even have a precise statement of what the invariant is.  The advantage+of the preserve-orientation plan is that it is extremely cheap to implement,+and apparently works beautifully.++--- Alternative plan (1) ---+Rather than have an ill-defined invariant, another possiblity is to+elminate those fresh unification variables at birth, when generating+the new fundep-inspired equalities.++The key idea is to call `instFlexiX` in `emitFunDepWanteds` on only those+type variables that are guaranteed to give us some progress. This means we+have to locally (without calling emitWanteds) identify the type variables+that do not give us any progress.  In the above example, we _know_ that+emitting the two wanteds `kco` and `co` is fruitless.++  Q: How do we identify such no-ops?++  1. Generate a matching substitution from LHS to RHS+        ɸ = [kb0 :-> k0, b0 :->  y0]+  2. Call `instFlexiX` on only those type variables that do not appear in the domain of ɸ+        ɸ' = instFlexiX ɸ (tvs - domain ɸ)+  3. Apply ɸ' on LHS and then call emitWanteds+        unifyWanteds ... (subst ɸ' LHS) RHS++Why will this work?  The matching substitution ɸ will be a best effort+substitution that gives us all the easy solutions. It can be generated with+modified version of `Core/Unify.unify_tys` where we run it in a matching mode+and never generate `SurelyApart` and always return a `MaybeApart Subst`+instead.++The same alternative plan would work for type-family injectivity constraints:+see Note [Improvement orientation].+--- End of Alternative plan (1) ---++--- Alternative plan (2) ---+We could have a new flavour of TcTyVar (like `TauTv`, `TyVarTv` etc; see GHC.Tc.Utils.TcType.MetaInfo)+for the fresh unification variables introduced by functional dependencies.  Say `FunDepTv`.  Then in+GHC.Tc.Utils.Unify.swapOverTyVars we could arrange to keep a `FunDepTv` on the left if possible.+Looks possible, but it's one more complication.+--- End of Alternative plan (2) ---+++--- Historical note: Failed Alternative Plan (3) ---+Previously we used a flag `cc_fundeps` in `CDictCan`. It would flip to False+once we used a fun dep to hint the solver to break and to stop emitting more+wanteds.  This solution was not complete, and caused a failures while trying+to solve for transitive functional dependencies (test case: T21703)+-- End of Historical note: Failed Alternative Plan (3) --+ Note [Weird fundeps] ~~~~~~~~~~~~~~~~~~~~ Consider   class Het a b | a -> b where@@ -1813,22 +1900,15 @@ doTopFundepImprovement :: Ct -> TcS (StopOrContinue Ct) -- Try to functional-dependency improvement between the constraint -- and the top-level instance declarations--- See Note [Fundeps with instances]+-- See Note [Fundeps with instances, and equality orientation] -- See also Note [Weird fundeps] doTopFundepImprovement work_item@(CDictCan { cc_ev = ev, cc_class = cls-                                           , cc_tyargs = xis-                                           , cc_fundeps = has_fds })-  | has_fds+                                           , cc_tyargs = xis })   = do { traceTcS "try_fundeps" (ppr work_item)        ; instEnvs <- getInstEnvs        ; let fundep_eqns = improveFromInstEnv instEnvs mk_ct_loc cls xis-       ; case fundep_eqns of-           [] -> continueWith work_item  -- No improvement-           _  -> do { emitFunDepWanteds (ctEvRewriters ev) fundep_eqns-                    ; continueWith (work_item { cc_fundeps = False }) } }-  | otherwise-  = continueWith work_item-+       ; emitFunDepWanteds (ctEvRewriters ev) fundep_eqns+       ; continueWith work_item }   where      dict_pred   = mkClassPred cls xis      dict_loc    = ctEvLoc ev@@ -1846,7 +1926,10 @@  emitFunDepWanteds :: RewriterSet  -- from the work item                   -> [FunDepEqn (CtLoc, RewriterSet)] -> TcS ()++emitFunDepWanteds _ [] = return () -- common case noop -- See Note [FunDep and implicit parameter reactions]+ emitFunDepWanteds work_rewriters fd_eqns   = mapM_ do_one_FDEqn fd_eqns   where@@ -2128,6 +2211,9 @@  Note [Improvement orientation] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See also Note [Fundeps with instances, and equality orientation], which describes+the Exact Same Prolem, with the same solution, but for functional dependencies.+ A very delicate point is the orientation of equalities arising from injectivity improvement (#12522).  Suppose we have   type family F x = t | t -> x@@ -2277,11 +2363,9 @@ -- See Note [Instance and Given overlap]   | not (xopt LangExt.IncoherentInstances dflags)   , not (naturallyCoherentClass clas)-  , let matchable_givens = matchableGivens loc pred inerts-  , not (isEmptyBag matchable_givens)+  , not (noMatchableGivenDicts inerts loc clas tys)   = do { traceTcS "Delaying instance application" $-           vcat [ text "Work item=" <+> pprClassPred clas tys-                , text "Potential matching givens:" <+> ppr matchable_givens ]+           vcat [ text "Work item=" <+> pprClassPred clas tys ]        ; return NotSure }    | otherwise@@ -2574,7 +2658,7 @@ impliedBySCs c1 c2 = all in_c2 c1   where     in_c2 :: TcPredType -> Bool-    in_c2 pred = any (pred `eqType`) c2_expanded+    in_c2 pred = any (pred `tcEqType`) c2_expanded      c2_expanded :: [TcPredType]  -- Includes all superclasses     c2_expanded = [ q | p <- c2, q <- p : transSuperClasses p ]
compiler/GHC/Tc/Solver/Monad.hs view
@@ -8,7 +8,7 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ViewPatterns #-} -{-# OPTIONS_GHC -Wno-incomplete-record-updates -Wno-orphans #-}+{-# OPTIONS_GHC -Wno-orphans #-}  -- | Monadic definitions for the constraint solver module GHC.Tc.Solver.Monad (@@ -131,27 +131,29 @@ import qualified GHC.Tc.Utils.Env      as TcM        ( checkWellStaged, tcGetDefaultTys, tcLookupClass, tcLookupId, topIdLvl        , tcInitTidyEnv )++import GHC.Driver.Session+ import GHC.Tc.Instance.Class( InstanceWhat(..), safeOverlap, instanceReturnsDictCon ) import GHC.Tc.Utils.TcType-import GHC.Driver.Session+import GHC.Tc.Solver.Types+import GHC.Tc.Solver.InertSet+import GHC.Tc.Types.Evidence+import GHC.Tc.Errors.Types+ import GHC.Core.Type import qualified GHC.Core.TyCo.Rep as Rep  -- this needs to be used only very locally import GHC.Core.Coercion import GHC.Core.Reduction--import GHC.Tc.Solver.Types-import GHC.Tc.Solver.InertSet--import GHC.Tc.Types.Evidence import GHC.Core.Class import GHC.Core.TyCon-import GHC.Tc.Errors.Types-import GHC.Types.Error ( mkPlainError, noHints ) +import GHC.Types.Error ( mkPlainError, noHints ) import GHC.Types.Name import GHC.Types.TyThing-import GHC.Unit.Module ( HasModule, getModule, extractModule ) import GHC.Types.Name.Reader ( GlobalRdrEnv, GlobalRdrElt )++import GHC.Unit.Module ( HasModule, getModule, extractModule ) import qualified GHC.Rename.Env as TcM import GHC.Types.Var import GHC.Types.Var.Env@@ -534,7 +536,7 @@     get_pending :: Ct -> [Ct] -> [Ct]  -- Get dicts with cc_pend_sc = True                                        -- but flipping the flag     get_pending dict dicts-        | Just dict' <- isPendingScDict dict+        | Just dict' <- pendingScDict_maybe dict         , belongs_to_this_level (ctEvidence dict)         = dict' : dicts         | otherwise@@ -547,7 +549,7 @@      get_pending_inst :: [Ct] -> QCInst -> ([Ct], QCInst)     get_pending_inst cts qci@(QCI { qci_ev = ev })-       | Just qci' <- isPendingScInst qci+       | Just qci' <- pendingScInst_maybe qci        , belongs_to_this_level ev        = (CQuantCan qci' : cts, qci')        | otherwise@@ -1684,7 +1686,7 @@   = -- See Note [Yukky eq_sel for a HoleDest]     do { let co_var = coHoleCoVar hole        ; setEvBind (mkWantedEvBind co_var tm)-       ; fillCoercionHole hole (mkTcCoVarCo co_var) }+       ; fillCoercionHole hole (mkCoVarCo co_var) }  setWantedEvTerm (EvVarDest ev_id) tm   = setEvBind (mkWantedEvBind ev_id tm)@@ -1940,7 +1942,7 @@                               -- causing trouble? See Detail (5) of Note.       = do { let (fun_args, extra_args) = splitAt (tyConArity tc) tys                  fun_app                = mkTyConApp tc fun_args-                 fun_app_kind           = tcTypeKind fun_app+                 fun_app_kind           = typeKind fun_app            ; fun_redn <- emit_work fun_app_kind fun_app            ; arg_redns <- unzipRedns <$> mapM go extra_args            ; return $ mkAppRedns fun_redn arg_redns }@@ -2010,5 +2012,5 @@ rewriterView :: TcType -> Maybe TcType rewriterView ty@(Rep.TyConApp tc _)   | isForgetfulSynTyCon tc || (isTypeSynonymTyCon tc && not (isFamFreeTyCon tc))-  = tcView ty+  = coreView ty rewriterView _other = Nothing
compiler/GHC/Tc/Solver/Rewrite.hs view
@@ -2,8 +2,6 @@  {-# LANGUAGE DeriveFunctor #-} -{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}- module GHC.Tc.Solver.Rewrite(    rewrite, rewriteArgsNom,    rewriteType@@ -40,8 +38,10 @@ import GHC.Exts (oneShot) import Control.Monad import Control.Applicative (liftA3)-import GHC.Builtin.Types.Prim (tYPETyCon)+import GHC.Builtin.Types (tYPETyCon) import Data.List ( find )+import GHC.Data.List.Infinite (Infinite)+import qualified GHC.Data.List.Infinite as Inf  {- ************************************************************************@@ -275,8 +275,8 @@  Key invariants:   (F0) co :: zonk(ty') ~ xi   where zonk(ty') ~ zonk(ty)-  (F1) tcTypeKind(xi) succeeds and returns a fully zonked kind-  (F2) tcTypeKind(xi) `eqType` zonk(tcTypeKind(ty))+  (F1) typeKind(xi) succeeds and returns a fully zonked kind+  (F2) typeKind(xi) `eqType` zonk(typeKind(ty))  Note that it is rewrite's job to try to reduce *every type function it sees*. @@ -297,14 +297,14 @@ when (co :: ty ~ xi) is important even before we zonk the whole program. For example, see the RTRNotFollowed case in rewriteTyVar. -Why have these invariants on rewriting? Because we sometimes use tcTypeKind+Why have these invariants on rewriting? Because we sometimes use typeKind during canonicalisation, and we want this kind to be zonked (e.g., see GHC.Tc.Solver.Canonical.canEqCanLHS).  Rewriting is always homogeneous. That is, the kind of the result of rewriting is always the same as the kind of the input, modulo zonking. More formally: -  (F2) zonk(tcTypeKind(ty)) `eqType` tcTypeKind(xi)+  (F2) zonk(typeKind(ty)) `eqType` typeKind(xi)  This invariant means that the kind of a rewritten type might not itself be rewritten. @@ -368,7 +368,7 @@ {-# INLINE rewrite_args_tc #-} rewrite_args_tc   :: TyCon         -- T-  -> Maybe [Role]  -- Nothing: ambient role is Nominal; all args are Nominal+  -> Maybe (Infinite Role)  -- Nothing: ambient role is Nominal; all args are Nominal                    -- Otherwise: no assumptions; use roles provided   -> [Type]   -> RewriteM ArgsReductions -- See the commentary on rewrite_args@@ -389,16 +389,16 @@     -- NB: Those bangs there drop allocations in T9872{a,c,d} by 8%.  {-# INLINE rewrite_args #-}-rewrite_args :: [TyCoBinder] -> Bool -- Binders, and True iff any of them are+rewrite_args :: [PiTyBinder] -> Bool -- Binders, and True iff any of them are                                      -- named.              -> Kind -> TcTyCoVarSet -- function kind; kind's free vars-             -> Maybe [Role] -> [Type]    -- these are in 1-to-1 correspondence+             -> Maybe (Infinite Role) -> [Type]    -- these are in 1-to-1 correspondence                                           -- Nothing: use all Nominal              -> RewriteM ArgsReductions -- This function returns ArgsReductions (Reductions cos xis) res_co --   coercions: co_i :: ty_i ~ xi_i, at roles given --   types:     xi_i---   coercion:  res_co :: tcTypeKind(fun tys) ~N tcTypeKind(fun xis)+--   coercion:  res_co :: typeKind(fun tys) ~N typeKind(fun xis) -- That is, the result coercion relates the kind of some function (whose kind is -- passed as the first parameter) instantiated at tys to the kind of that -- function instantiated at the xis. This is useful in keeping rewriting@@ -413,7 +413,7 @@   = case (orig_m_roles, any_named_bndrs) of       (Nothing, False) -> rewrite_args_fast orig_tys       _ -> rewrite_args_slow orig_binders orig_inner_ki orig_fvs orig_roles orig_tys-        where orig_roles = fromMaybe (repeat Nominal) orig_m_roles+        where orig_roles = fromMaybe (Inf.repeat Nominal) orig_m_roles  {-# INLINE rewrite_args_fast #-} -- | fast path rewrite_args, in which none of the binders are named and@@ -437,11 +437,11 @@ {-# INLINE rewrite_args_slow #-} -- | Slow path, compared to rewrite_args_fast, because this one must track -- a lifting context.-rewrite_args_slow :: [TyCoBinder] -> Kind -> TcTyCoVarSet-                  -> [Role] -> [Type]+rewrite_args_slow :: [PiTyBinder] -> Kind -> TcTyCoVarSet+                  -> Infinite Role -> [Type]                   -> RewriteM ArgsReductions rewrite_args_slow binders inner_ki fvs roles tys-  = do { rewritten_args <- zipWithM rw roles tys+  = do { rewritten_args <- zipWithM rw (Inf.toList roles) tys        ; return (simplifyArgsWorker binders inner_ki fvs roles rewritten_args) }   where     {-# INLINE rw #-}@@ -587,9 +587,9 @@   = do { het_redn <- case tcSplitTyConApp_maybe fun_xi of            Just (tc, xis) ->              do { let tc_roles  = tyConRolesRepresentational tc-                      arg_roles = dropList xis tc_roles+                      arg_roles = Inf.dropList xis tc_roles                 ; ArgsReductions (Reductions arg_cos arg_xis) kind_co-                    <- rewrite_vector (tcTypeKind fun_xi) arg_roles arg_tys+                    <- rewrite_vector (typeKind fun_xi) arg_roles arg_tys                    -- We start with a reduction of the form                   --   fun_co :: ty ~ T xi_1 ... xi_n@@ -606,9 +606,9 @@                       app_co = case eq_rel of                         NomEq  -> mkAppCos fun_co arg_cos                         ReprEq -> mkAppCos fun_co (map mkNomReflCo arg_tys)-                                  `mkTcTransCo`-                                  mkTcTyConAppCo Representational tc-                                    (zipWith mkReflCo tc_roles xis ++ arg_cos)+                                  `mkTransCo`+                                  mkTyConAppCo Representational tc+                                    (zipWith mkReflCo (Inf.toList tc_roles) xis ++ arg_cos)                  ; return $                     mkHetReduction@@ -616,7 +616,7 @@                       kind_co }            Nothing ->              do { ArgsReductions redns kind_co-                    <- rewrite_vector (tcTypeKind fun_xi) (repeat Nominal) arg_tys+                    <- rewrite_vector (typeKind fun_xi) (Inf.repeat Nominal) arg_tys                 ; return $ mkHetReduction (mkAppRedns fun_redn redns) kind_co }         ; role <- getRole@@ -636,7 +636,7 @@  -- Rewrite a vector (list of arguments). rewrite_vector :: Kind   -- of the function being applied to these arguments-               -> [Role] -- If we're rewriting w.r.t. ReprEq, what roles do the+               -> Infinite Role -- If we're rewriting w.r.t. ReprEq, what roles do the                          -- args have?                -> [Type] -- the args to rewrite                -> RewriteM ArgsReductions@@ -1053,7 +1053,7 @@  -- | Like 'splitPiTys'' but comes with a 'Bool' which is 'True' iff there is at -- least one named binder.-split_pi_tys' :: Type -> ([TyCoBinder], Type, Bool)+split_pi_tys' :: Type -> ([PiTyBinder], Type, Bool) split_pi_tys' ty = split ty ty   where      -- put common cases first@@ -1064,20 +1064,20 @@   split _       (FunTy { ft_af = af, ft_mult = w, ft_arg = arg, ft_res = res })                                  = let -- See #19102                                        !(bs, ty, named) = split res res-                                   in  (Anon af (mkScaled w arg) : bs, ty, named)+                                   in  (Anon (mkScaled w arg) af : bs, ty, named)    split orig_ty ty | Just ty' <- coreView ty = split orig_ty ty'   split orig_ty _                = ([], orig_ty, False) {-# INLINE split_pi_tys' #-} --- | Like 'tyConBindersTyCoBinders' but you also get a 'Bool' which is true iff+-- | Like 'tyConBindersPiTyBinders' but you also get a 'Bool' which is true iff -- there is at least one named binder.-ty_con_binders_ty_binders' :: [TyConBinder] -> ([TyCoBinder], Bool)+ty_con_binders_ty_binders' :: [TyConBinder] -> ([PiTyBinder], Bool) ty_con_binders_ty_binders' = foldr go ([], False)   where     go (Bndr tv (NamedTCB vis)) (bndrs, _)       = (Named (Bndr tv vis) : bndrs, True)     go (Bndr tv (AnonTCB af))   (bndrs, n)-      = (Anon af (tymult (tyVarKind tv)) : bndrs, n)+      = (Anon (tymult (tyVarKind tv)) af : bndrs, n)     {-# INLINE go #-} {-# INLINE ty_con_binders_ty_binders' #-}
compiler/GHC/Tc/TyCl.hs view
@@ -107,7 +107,6 @@ import Data.List ( partition) import Data.List.NonEmpty ( NonEmpty(..) ) import qualified Data.List.NonEmpty as NE-import qualified Data.Set as Set import Data.Tuple( swap )  {-@@ -982,7 +981,7 @@ around even between minor released. By forbidding visible type application, we ensure users aren't caught unawares. -Go read Note [VarBndrs, TyCoVarBinders, TyConBinders, and visibility] in GHC.Core.TyCo.Rep.+Go read Note [VarBndrs, ForAllTyBinders, TyConBinders, and visibility] in GHC.Core.TyCo.Rep.  The question for this Note is this:    given a TyClDecl, how are its quantified type variables classified?@@ -2380,7 +2379,7 @@   , HsDataDefn { dd_derivs = derivs } <- dataDefn   = [ DerivInfo { di_rep_tc = tycon                 , di_scoped_tvs =-                    if isFunTyCon tycon || isPrimTyCon tycon+                    if isPrimTyCon tycon                        then []  -- no tyConTyVars                        else mkTyVarNamePairs (tyConTyVars tycon)                 , di_clauses = derivs@@ -2981,9 +2980,10 @@       = return AbstractTyCon      mk_tc_rhs _ tycon data_cons = case data_cons of-          DataTypeCons _ data_cons -> return $+          DataTypeCons is_type_data data_cons -> return $                         mkLevPolyDataTyConRhs                           (isFixedRuntimeRepKind (tyConResKind tycon))+                          is_type_data                           data_cons           NewTypeCon data_con -> mkNewTyConRhs tc_name tycon data_con @@ -3431,8 +3431,8 @@        ; let tc_tvs   = binderVars tc_bndrs              fake_ty  = mkSpecForAllTys  tc_tvs      $                         mkInvisForAllTys exp_tvbndrs $-                        mkPhiTy ctxt $-                        mkVisFunTys arg_tys $+                        tcMkPhiTy ctxt               $+                        tcMkScaledFunTys arg_tys     $                         unitTy              -- That type is a lie, of course. (It shouldn't end in ()!)              -- And we could construct a proper result type from the info@@ -3537,8 +3537,8 @@         ; tkvs <- kindGeneralizeAll skol_info                     (mkInvisForAllTys outer_tv_bndrs $-                     mkPhiTy ctxt                    $-                     mkVisFunTys arg_tys             $+                     tcMkPhiTy ctxt                  $+                     tcMkScaledFunTys arg_tys        $                      res_ty)        ; traceTc "tcConDecl:GADT" (ppr names $$ ppr res_ty $$ ppr tkvs)        ; reportUnsolvedEqualities skol_info tkvs tclvl wanted@@ -3847,10 +3847,12 @@         -- since the dcUserTyVarBinders invariant guarantees that the         -- substitution has *all* the tyvars in its domain.         -- See Note [DataCon user type variable binders] in GHC.Core.DataCon.-        subst_user_tvs  = mapVarBndrs (getTyVar "rejigConRes" . substTyVar arg_subst)+        subst_user_tvs  = mapVarBndrs (substTyVarToTyVar arg_subst)         substed_tvbndrs = subst_user_tvs dc_tvbndrs -        substed_eqs = map (substEqSpec arg_subst) raw_eqs+        substed_eqs = [ mkEqSpec (substTyVarToTyVar arg_subst tv)+                                 (substTy arg_subst ty)+                      | (tv,ty) <- raw_eqs ]     in     (univ_tvs, substed_ex_tvs, substed_tvbndrs, substed_eqs, arg_subst) @@ -4016,7 +4018,7 @@            -> Subst   -- ^ The matching between the template result type                          -- and the actual result type            -> ( [TyVar]-              , [EqSpec]+              , [(TyVar,Type)]   -- The un-substituted eq-spec               , Subst ) -- ^ The univ. variables, the GADT equalities,                            -- and a subst to apply to the GADT equalities                            -- and existentials.@@ -4027,13 +4029,13 @@                `unionInScope` getSubstInScope subst     empty_subst = mkEmptySubst in_scope -    choose :: [TyVar]           -- accumulator of univ tvs, reversed-           -> [EqSpec]          -- accumulator of GADT equalities, reversed+    choose :: [TyVar]        -- accumulator of univ tvs, reversed+           -> [(TyVar,Type)] -- accumulator of GADT equalities, reversed            -> Subst          -- template substitution            -> Subst          -- res. substitution            -> [TyVar]           -- template tvs (the univ tvs passed in)            -> ( [TyVar]         -- the univ_tvs-              , [EqSpec]        -- GADT equalities+              , [(TyVar,Type)]  -- GADT equalities               , Subst )       -- a substitution to fix kinds in ex_tvs      choose univs eqs _t_sub r_sub []@@ -4045,6 +4047,8 @@             |  not (r_tv `elem` univs)             ,  tyVarKind r_tv `eqType` (substTy t_sub (tyVarKind t_tv))             -> -- simple, well-kinded variable substitution.+               -- the name of the universal comes from the result of the ctor+               -- see (R2) of Note [DataCon user type variable binders] in GHC.Core.DataCon                choose (r_tv:univs) eqs                       (extendTvSubst t_sub t_tv r_ty')                       (extendTvSubst r_sub r_tv r_ty')@@ -4054,13 +4058,19 @@               r_ty'  = mkTyVarTy r_tv1                 -- Not a simple substitution: make an equality predicate-          _ -> choose (t_tv':univs) (mkEqSpec t_tv' r_ty : eqs)+               -- the name of the universal comes from the datatype header+               -- see (R2) of Note [DataCon user type variable binders] in GHC.Core.DataCon+          _ -> choose (t_tv':univs) eqs'                       (extendTvSubst t_sub t_tv (mkTyVarTy t_tv'))                          -- We've updated the kind of t_tv,                          -- so add it to t_sub (#14162)                       r_sub t_tvs             where-              t_tv' = updateTyVarKind (substTy t_sub) t_tv+              tv_kind  = tyVarKind t_tv+              tv_kind' = substTy t_sub tv_kind+              t_tv'    = setTyVarKind t_tv tv_kind'+              eqs' | isConstraintLikeKind (typeKind tv_kind') = eqs+                   | otherwise = (t_tv', r_ty) : eqs        | otherwise       = pprPanic "mkGADTVars" (ppr tmpl_tvs $$ ppr subst)@@ -4343,9 +4353,7 @@     is_exhaustive = all (dataConCannotMatch inst_tys) cons_without_field      con1 = assert (not (null cons_with_field)) $ head cons_with_field-    (univ_tvs, _, eq_spec, _, _, _) = dataConFullSig con1-    eq_subst = mkTvSubstPrs (map eqSpecPair eq_spec)-    inst_tys = substTyVars eq_subst univ_tvs+    inst_tys = dataConResRepTyArgs con1  checkFieldCompat :: FieldLabelString -> DataCon -> DataCon                  -> Type -> Type -> Type -> Type -> TcM ()@@ -4368,8 +4376,8 @@          ; traceTc "checkValidDataCon" (vcat               [ ppr con, ppr tc, ppr tc_tvs-              , ppr res_ty_tmpl <+> dcolon <+> ppr (tcTypeKind res_ty_tmpl)-              , ppr orig_res_ty <+> dcolon <+> ppr (tcTypeKind orig_res_ty)])+              , ppr res_ty_tmpl <+> dcolon <+> ppr (typeKind res_ty_tmpl)+              , ppr orig_res_ty <+> dcolon <+> ppr (typeKind orig_res_ty)])           -- Check that the return type of the data constructor@@ -4499,17 +4507,8 @@           -- checked here because we sometimes build invalid DataCons before           -- erroring above here         ; when debugIsOn $-          do { let (univs, exs, eq_spec, _, _, _) = dataConFullSig con-                   user_tvs                       = dataConUserTyVars con-                   user_tvbs_invariant-                     =    Set.fromList (filterEqSpec eq_spec univs ++ exs)-                       == Set.fromList user_tvs-             ; massertPpr user_tvbs_invariant-                          $ vcat ([ ppr con-                               , ppr univs-                               , ppr exs-                               , ppr eq_spec-                               , ppr user_tvs ]) }+          massertPpr (checkDataConTyVars con) $+          ppr con $$  ppr (dataConFullSig con) $$ ppr (dataConUserTyVars con)          ; traceTc "Done validity of data con" $           vcat [ ppr con@@ -4575,8 +4574,8 @@     ok_bang (HsSrcBang _ _ SrcLazy)   = False     ok_bang _                         = True -    ok_mult One = True-    ok_mult _   = False+    ok_mult OneTy = True+    ok_mult _     = False   -- | Reject nullary data constructors where a type variable@@ -4585,7 +4584,7 @@ checkEscapingKind :: DataCon -> TcM () checkEscapingKind data_con   | null eq_spec, null theta, null arg_tys-  , let tau_kind = tcTypeKind res_ty+  , let tau_kind = typeKind res_ty   , Nothing <- occCheckExpand (univ_tvs ++ ex_tvs) tau_kind     -- Ensure that none of the tvs occur in the kind of the forall     -- /after/ expanding type synonyms.@@ -5097,7 +5096,7 @@     check_dc_roles datacon       = do { traceTc "check_dc_roles" (ppr datacon <+> ppr (tyConRoles tc))            ; mapM_ (check_ty_roles role_env Representational) $-                    eqSpecPreds eq_spec ++ theta ++ (map scaledThing arg_tys) }+             eqSpecPreds eq_spec ++ theta ++ map scaledThing arg_tys }                     -- See Note [Role-checking data constructor arguments] in GHC.Tc.TyCl.Utils       where         (univ_tvs, ex_tvs, eq_spec, theta, arg_tys, _res_ty)
compiler/GHC/Tc/TyCl/Build.hs view
@@ -18,26 +18,29 @@ import GHC.Prelude  import GHC.Iface.Env-import GHC.Core.FamInstEnv( FamInstEnvs, mkNewTypeCoAxiom ) import GHC.Builtin.Types( isCTupleTyConName, unboxedUnitTy )++import GHC.Tc.Utils.TcType+import GHC.Tc.Utils.Monad+ import GHC.Core.DataCon import GHC.Core.PatSyn+import GHC.Core.Class+import GHC.Core.TyCon+import GHC.Core.Type+import GHC.Core.Multiplicity+import GHC.Core.FamInstEnv( FamInstEnvs, mkNewTypeCoAxiom )++import GHC.Types.SrcLoc( SrcSpan, noSrcSpan ) import GHC.Types.Var import GHC.Types.Var.Set import GHC.Types.Basic import GHC.Types.Name import GHC.Types.Name.Env import GHC.Types.Id.Make-import GHC.Core.Class-import GHC.Core.TyCon-import GHC.Core.Type import GHC.Types.SourceText-import GHC.Tc.Utils.TcType-import GHC.Core.Multiplicity--import GHC.Types.SrcLoc( SrcSpan, noSrcSpan )-import GHC.Tc.Utils.Monad import GHC.Types.Unique.Supply+ import GHC.Utils.Misc import GHC.Utils.Outputable import GHC.Utils.Panic@@ -175,7 +178,7 @@               data_con = mkDataCon src_name declared_infix prom_info                                    src_bangs field_lbls                                    univ_tvs ex_tvs user_tvbs eq_spec ctxt-                                   arg_tys res_ty NoRRI rep_tycon tag+                                   arg_tys res_ty NoPromInfo rep_tycon tag                                    stupid_ctxt dc_wrk dc_rep               dc_wrk = mkDataConWorkId work_name data_con               dc_rep = initUs_ us (mkDataConRep dc_bang_opts fam_envs wrap_name data_con)@@ -320,22 +323,20 @@               -- (We used to call them D_C, but now we can have two different               --  superclasses both called C!) -        ; let use_newtype = isSingleton arg_tys+        ; let use_newtype = isSingleton (sc_theta ++ op_tys)                 -- Use a newtype if the data constructor                 --   (a) has exactly one value field                 --       i.e. exactly one operation or superclass taken together                 --   (b) that value is of lifted type (which they always are, because                 --       we box equality superclasses)                 -- See Note [Class newtypes and equality predicates]--                -- We treat the dictionary superclasses as ordinary arguments.-                -- That means that in the case of+                --+                -- In the case of                 --     class C a => D a-                -- we don't get a newtype with no arguments!+                -- we use a newtype, but with one superclass and no arguments               args       = sc_sel_names ++ op_names               op_tys     = [ty | (_,ty,_) <- sig_stuff]               op_names   = [op | (op,_,_) <- sig_stuff]-              arg_tys    = sc_theta ++ op_tys               rec_tycon  = classTyCon rec_clas               univ_bndrs = tyConInvisTVBinders binders               univ_tvs   = binderVars univ_bndrs@@ -353,8 +354,8 @@                                    [{- no existentials -}]                                    univ_bndrs                                    [{- No GADT equalities -}]-                                   [{- No theta -}]-                                   (map unrestricted arg_tys) -- type classes are unrestricted+                                   sc_theta+                                   (map unrestricted op_tys) -- type classes are unrestricted                                    (mkTyConApp rec_tycon (mkTyVarTys univ_tvs))                                    rec_tycon                                    (mkTyConTagMap rec_tycon)
compiler/GHC/Tc/TyCl/Class.hs view
@@ -290,7 +290,7 @@               ctxt = FunSigCtxt sel_name warn_redundant -       ; let local_dm_id = mkLocalId local_dm_name Many local_dm_ty+       ; let local_dm_id = mkLocalId local_dm_name ManyTy local_dm_ty              local_dm_sig = CompleteSig { sig_bndr = local_dm_id                                         , sig_ctxt  = ctxt                                         , sig_loc   = getLocA hs_ty }
compiler/GHC/Tc/TyCl/Instance.hs view
@@ -8,7 +8,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-} -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-} {-# OPTIONS_GHC -Wno-incomplete-record-updates #-}  -- | Typechecking instance declarations@@ -81,7 +80,7 @@ import GHC.Utils.Panic import GHC.Types.SrcLoc import GHC.Utils.Misc-import GHC.Data.BooleanFormula ( isUnsatisfied, pprBooleanFormulaNice )+import GHC.Data.BooleanFormula ( isUnsatisfied ) import qualified GHC.LanguageExtensions as LangExt  import Control.Monad@@ -498,8 +497,8 @@               -- Map from the skolemized Names to the original Names.               -- See Note [Associated data family instances and di_scoped_tvs].               tv_skol_env = mkVarEnv $ map swap tv_skol_prs-              n_inferred = countWhile ((== Inferred) . binderArgFlag) $-                           fst $ splitForAllTyCoVarBinders dfun_ty+              n_inferred = countWhile ((== Inferred) . binderFlag) $+                           fst $ splitForAllForAllTyBinders dfun_ty               visible_skol_tvs = drop n_inferred skol_tvs          ; traceTc "tcLocalInstDecl 1" (ppr dfun_ty $$ ppr (invisibleTyBndrCount dfun_ty) $$ ppr skol_tvs)@@ -591,7 +590,7 @@           -- (0) Check it's an open type family        ; checkTc (isTypeFamilyTyCon fam_tc)     (wrongKindOfFamily fam_tc)-       ; checkTc (isOpenTypeFamilyTyCon fam_tc) (notOpenFamily fam_tc)+       ; checkTc (isOpenTypeFamilyTyCon fam_tc) (TcRnNotOpenFamily fam_tc)           -- (1) do the work of verifying the synonym group          -- For some reason we don't have a location for the equation@@ -618,16 +617,16 @@        ; traceTc "tcFamInstDecl" (ppr fam_tc)        ; type_families <- xoptM LangExt.TypeFamilies        ; is_boot       <- tcIsHsBootOrSig   -- Are we compiling an hs-boot file?-       ; checkTc type_families $ badFamInstDecl fam_tc-       ; checkTc (not is_boot) $ badBootFamInstDeclErr+       ; checkTc type_families (TcRnBadFamInstDecl fam_tc)+       ; checkTc (not is_boot) TcRnBadBootFamInstDecl         -- Check that it is a family TyCon, and that        -- oplevel type instances are not for associated types.-       ; checkTc (isFamilyTyCon fam_tc) (notFamily fam_tc)+       ; checkTc (isFamilyTyCon fam_tc) (TcRnIllegalFamilyInstance fam_tc)         ; when (isNotAssociated mb_clsinfo &&   -- Not in a class decl                isTyConAssoc fam_tc)            -- but an associated type-              (addErr $ assocInClassErr fam_tc)+              (addErr $ TcRnMissingClassAssoc fam_tc)        }  {- Note [Associated type instances]@@ -772,9 +771,10 @@               ; rep_tc_name <- newFamInstTyConName lfam_name pats               ; axiom_name  <- newFamInstAxiomName lfam_name [pats]               ; tc_rhs <- case data_cons of-                     DataTypeCons _ data_cons -> return $+                     DataTypeCons type_data data_cons -> return $                         mkLevPolyDataTyConRhs                           (isFixedRuntimeRepKind res_kind)+                          type_data                           data_cons                      NewTypeCon data_con -> mkNewTyConRhs rep_tc_name rec_rep_tc data_con @@ -1283,7 +1283,7 @@        ; self_dict <- newDict clas inst_tys        ; let class_tc      = classTyCon clas              loc'          = noAnnSrcSpan loc-             [dict_constr] = tyConDataCons class_tc+             dict_constr   = tyConSingleDataCon class_tc              dict_bind = mkVarBind self_dict (L loc' con_app_args)                       -- We don't produce a binding for the dict_constr; instead we@@ -1367,7 +1367,7 @@    ev_ids      = mkTemplateLocalsNum 1                    dfun_theta    dfun_bndrs  = dfun_tvs ++ ev_ids    clas_tc     = classTyCon clas-   [dict_con]  = tyConDataCons clas_tc+   dict_con    = tyConSingleDataCon clas_tc    is_newtype  = isNewTyCon clas_tc  wrapId :: HsWrapper -> Id -> HsExpr GhcTc@@ -1467,9 +1467,8 @@            ; sc_top_name  <- newName (mkSuperDictAuxOcc n (getOccName cls))            ; sc_ev_id     <- newEvVar sc_pred            ; addTcEvBind ev_binds_var $ mkWantedEvBind sc_ev_id sc_ev_tm-           ; let sc_top_ty = mkInfForAllTys tyvars $-                             mkPhiTy (map idType dfun_evs) sc_pred-                 sc_top_id = mkLocalId sc_top_name Many sc_top_ty+           ; let sc_top_ty = tcMkDFunSigmaTy tyvars (map idType dfun_evs) sc_pred+                 sc_top_id = mkLocalId sc_top_name ManyTy sc_top_ty                  export = ABE { abe_wrap = idHsWrapper                               , abe_poly = sc_top_id                               , abe_mono = sc_ev_id@@ -1782,7 +1781,7 @@         meth_tau     = classMethodInstTy sel_id inst_tys         error_string dflags = showSDoc dflags                               (hcat [ppr inst_loc, vbar, ppr sel_id ])-        lam_wrapper  = mkWpTyLams tyvars <.> mkWpLams dfun_ev_vars+        lam_wrapper  = mkWpTyLams tyvars <.> mkWpEvLams dfun_ev_vars      ----------------------     -- Check if one of the minimal complete definitions is satisfied@@ -1936,7 +1935,7 @@   = do { (sig_ty, hs_wrap)              <- setSrcSpan (getLocA hs_sig_ty) $                 do { inst_sigs <- xoptM LangExt.InstanceSigs-                   ; checkTc inst_sigs (misplacedInstSig sel_name hs_sig_ty)+                   ; checkTc inst_sigs (TcRnMisplacedInstSig sel_name hs_sig_ty)                    ; let ctxt = FunSigCtxt sel_name NoRRC                    ; sig_ty  <- tcHsSigType ctxt hs_sig_ty                    ; let local_meth_ty = idType local_meth_id@@ -1953,7 +1952,7 @@        ; let ctxt = FunSigCtxt sel_name (lhsSigTypeContextSpan hs_sig_ty)                     -- WantRCC <=> check for redundant constraints in the                     --          user-specified instance signature-             inner_meth_id  = mkLocalId inner_meth_name Many sig_ty+             inner_meth_id  = mkLocalId inner_meth_name ManyTy sig_ty              inner_meth_sig = CompleteSig { sig_bndr = inner_meth_id                                           , sig_ctxt = ctxt                                           , sig_loc  = getLocA hs_sig_ty }@@ -2002,8 +2001,8 @@         ; local_meth_name <- newName sel_occ                   -- Base the local_meth_name on the selector name, because                   -- type errors from tcMethodBody come from here-        ; let poly_meth_id  = mkLocalId poly_meth_name  Many poly_meth_ty-              local_meth_id = mkLocalId local_meth_name Many local_meth_ty+        ; let poly_meth_id  = mkLocalId poly_meth_name  ManyTy poly_meth_ty+              local_meth_id = mkLocalId local_meth_name ManyTy local_meth_ty          ; return (poly_meth_id, local_meth_id) }   where@@ -2024,14 +2023,6 @@                               , text "   Class sig:" <+> ppr meth_ty ])        ; return (env2, msg) } -misplacedInstSig :: Name -> LHsSigType GhcRn -> TcRnMessage-misplacedInstSig name hs_ty-  = mkTcRnUnknownMessage $ mkPlainError noHints $-    vcat [ hang (text "Illegal type signature in instance declaration:")-              2 (hang (pprPrefixName name)-                    2 (dcolon <+> ppr hs_ty))-         , text "(Use InstanceSigs to allow this)" ]- {- Note [Instance method signatures] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ With -XInstanceSigs we allow the user to supply a signature for the@@ -2122,7 +2113,7 @@                fn   = noLocA (idName sel_id)               visible_inst_tys = [ ty | (tcb, ty) <- tyConBinders (classTyCon clas) `zip` inst_tys-                                      , tyConBinderArgFlag tcb /= Inferred ]+                                      , tyConBinderForAllTyFlag tcb /= Inferred ]               rhs  = foldl' mk_vta (nlHsVar dm_name) visible_inst_tys               bind = L (noAnnSrcSpan loc)                     $ mkTopFunBind Generated fn@@ -2154,14 +2145,9 @@ warnUnsatisfiedMinimalDefinition :: ClassMinimalDef -> TcM () warnUnsatisfiedMinimalDefinition mindef   = do { warn <- woptM Opt_WarnMissingMethods-       ; let msg = mkTcRnUnknownMessage $-               mkPlainDiagnostic (WarningWithFlag Opt_WarnMissingMethods) noHints message+       ; let msg = TcRnUnsatisfiedMinimalDef mindef        ; diagnosticTc warn msg        }-  where-    message = vcat [text "No explicit implementation for"-                   ,nest 2 $ pprBooleanFormulaNice mindef-                   ]  {- Note [Export helper functions]@@ -2375,30 +2361,3 @@ inst_decl_ctxt doc = hang (text "In the instance declaration for")                         2 (quotes doc) -badBootFamInstDeclErr :: TcRnMessage-badBootFamInstDeclErr-  = mkTcRnUnknownMessage $ mkPlainError noHints $ text "Illegal family instance in hs-boot file"--notFamily :: TyCon -> TcRnMessage-notFamily tycon-  = mkTcRnUnknownMessage $ mkPlainError noHints $-    vcat [ text "Illegal family instance for" <+> quotes (ppr tycon)-         , nest 2 $ parens (ppr tycon <+> text "is not an indexed type family")]--assocInClassErr :: TyCon -> TcRnMessage-assocInClassErr name- = mkTcRnUnknownMessage $ mkPlainError noHints $-   text "Associated type" <+> quotes (ppr name) <+>-   text "must be inside a class instance"--badFamInstDecl :: TyCon -> TcRnMessage-badFamInstDecl tc_name-  = mkTcRnUnknownMessage $ mkPlainError noHints $-    vcat [ text "Illegal family instance for" <+>-           quotes (ppr tc_name)-         , nest 2 (parens $ text "Use TypeFamilies to allow indexed type families") ]--notOpenFamily :: TyCon -> TcRnMessage-notOpenFamily tc-  = mkTcRnUnknownMessage $ mkPlainError noHints $-  text "Illegal instance for closed family" <+> quotes (ppr tc)
compiler/GHC/Tc/TyCl/PatSyn.hs view
@@ -2,8 +2,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-} -{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}- {- (c) The University of Glasgow 2006 (c) The GRASP/AQUA Project, Glasgow University, 1992-1998@@ -21,17 +19,27 @@ import GHC.Prelude  import GHC.Hs+ import GHC.Tc.Gen.Pat-import GHC.Core.Multiplicity-import GHC.Core.Type ( tidyTyCoVarBinders, tidyTypes, tidyType, isManyDataConTy )-import GHC.Core.TyCo.Subst( extendTvSubstWithClone )+import GHC.Tc.Utils.Env+import GHC.Tc.Utils.TcMType+import GHC.Tc.Utils.Zonk import GHC.Tc.Errors.Types import GHC.Tc.Utils.Monad import GHC.Tc.Gen.Sig ( TcPragEnv, emptyPragEnv, completeSigFromId, lookupPragEnv                       , addInlinePrags, addInlinePragArity )-import GHC.Tc.Utils.Env-import GHC.Tc.Utils.TcMType-import GHC.Tc.Utils.Zonk+import GHC.Tc.Solver+import GHC.Tc.Utils.Unify+import GHC.Tc.Utils.TcType+import GHC.Tc.Types.Evidence+import GHC.Tc.Types.Origin+import GHC.Tc.TyCl.Build++import GHC.Core.Multiplicity+import GHC.Core.Type ( typeKind, tidyForAllTyBinders, tidyTypes, tidyType, isManyTy, mkTYPEapp )+import GHC.Core.TyCo.Subst( extendTvSubstWithClone )+import GHC.Core.Predicate+ import GHC.Builtin.Types.Prim import GHC.Types.Error import GHC.Types.Name@@ -47,14 +55,7 @@ import GHC.Types.Id.Info( RecSelParent(..) ) import GHC.Tc.Gen.Bind import GHC.Types.Basic-import GHC.Tc.Solver-import GHC.Tc.Utils.Unify-import GHC.Core.Predicate import GHC.Builtin.Types-import GHC.Tc.Utils.TcType-import GHC.Tc.Types.Evidence-import GHC.Tc.Types.Origin-import GHC.Tc.TyCl.Build import GHC.Types.Var.Set import GHC.Tc.TyCl.Utils import GHC.Core.ConLike@@ -214,8 +215,8 @@ -- See Note [Equality evidence in pattern synonyms] mkProvEvidence ev_id   | EqPred r ty1 ty2 <- classifyPredType pred-  , let k1 = tcTypeKind ty1-        k2 = tcTypeKind ty2+  , let k1 = typeKind ty1+        k2 = typeKind ty2         is_homo = k1 `tcEqType` k2         homo_tys   = [k1, ty1, ty2]         hetero_tys = [k1, k2, ty1, ty2]@@ -422,7 +423,7 @@              ex_tvs     = binderVars ex_bndrs           -- Pattern synonyms currently cannot be linear (#18806)-       ; checkTc (all (isManyDataConTy . scaledMult) arg_tys) $+       ; checkTc (all (isManyTy . scaledMult) arg_tys) $            TcRnLinearPatSyn sig_body_ty         ; skol_info <- mkSkolemInfo (SigSkol (PatSynCtxt name) pat_ty [])@@ -718,8 +719,8 @@        ; pat_ty'         <- zonkTcTypeToTypeX   ze pat_ty        ; arg_tys'        <- zonkTcTypesToTypesX ze arg_tys -       ; let (env1, univ_tvs) = tidyTyCoVarBinders emptyTidyEnv univ_tvs'-             (env2, ex_tvs)   = tidyTyCoVarBinders env1 ex_tvs'+       ; let (env1, univ_tvs) = tidyForAllTyBinders emptyTidyEnv univ_tvs'+             (env2, ex_tvs)   = tidyForAllTyBinders env1 ex_tvs'              req_theta  = tidyTypes env2 req_theta'              prov_theta = tidyTypes env2 prov_theta'              arg_tys    = tidyTypes env2 arg_tys'@@ -787,8 +788,8 @@                 (ex_tvs, ex_tys, prov_theta, prov_dicts)                 (args, arg_tys) pat_ty   = do { let loc' = locA loc-       ; rr_name <- newNameAt (mkTyVarOcc "rep") loc'-       ; tv_name <- newNameAt (mkTyVarOcc "r")   loc'+       ; rr_name <- newNameAt (mkTyVarOccFS (fsLit "rep")) loc'+       ; tv_name <- newNameAt (mkTyVarOccFS (fsLit "r"))   loc'        ; let rr_tv  = mkTyVar rr_name runtimeRepTy              rr     = mkTyVarTy rr_tv              res_tv = mkTyVar tv_name (mkTYPEapp rr)@@ -803,9 +804,9 @@              fail_ty  = mkVisFunTyMany unboxedUnitTy res_ty         ; matcher_name <- newImplicitBinder ps_name mkMatcherOcc-       ; scrutinee    <- newSysLocalId (fsLit "scrut") Many pat_ty-       ; cont         <- newSysLocalId (fsLit "cont")  Many cont_ty-       ; fail         <- newSysLocalId (fsLit "fail")  Many fail_ty+       ; scrutinee    <- newSysLocalId (fsLit "scrut") ManyTy pat_ty+       ; cont         <- newSysLocalId (fsLit "cont")  ManyTy cont_ty+       ; fail         <- newSysLocalId (fsLit "fail")  ManyTy fail_ty         ; dflags       <- getDynFlags        ; let matcher_tau   = mkVisFunTysMany [pat_ty, cont_ty, fail_ty] res_ty
compiler/GHC/Tc/TyCl/Utils.hs view
@@ -139,14 +139,15 @@      go_co (TyConAppCo _ tc cs)   = go_tc tc `plusNameEnv` go_co_s cs      go_co (AppCo co co')         = go_co co `plusNameEnv` go_co co'      go_co (ForAllCo _ co co')    = go_co co `plusNameEnv` go_co co'-     go_co (FunCo _ co_mult co co') = go_co co_mult `plusNameEnv` go_co co `plusNameEnv` go_co co'+     go_co (FunCo { fco_mult = m, fco_arg = a, fco_res = r })+                                  = go_co m `plusNameEnv` go_co a `plusNameEnv` go_co r      go_co (CoVarCo _)            = emptyNameEnv      go_co (HoleCo {})            = emptyNameEnv      go_co (AxiomInstCo _ _ cs)   = go_co_s cs      go_co (UnivCo p _ ty ty')    = go_prov p `plusNameEnv` go ty `plusNameEnv` go ty'      go_co (SymCo co)             = go_co co      go_co (TransCo co co')       = go_co co `plusNameEnv` go_co co'-     go_co (NthCo _ _ co)         = go_co co+     go_co (SelCo _ co)           = go_co co      go_co (LRCo _ co)            = go_co co      go_co (InstCo co co')        = go_co co `plusNameEnv` go_co co'      go_co (KindCo co)            = go_co co@@ -500,8 +501,8 @@   | otherwise             = pprPanic "initialRoleEnv1" (ppr tc)   where name         = tyConName tc         bndrs        = tyConBinders tc-        argflags     = map tyConBinderArgFlag bndrs-        num_exps     = count isVisibleArgFlag argflags+        argflags     = map tyConBinderForAllTyFlag bndrs+        num_exps     = count isVisibleForAllTyFlag argflags            -- if the number of annotations in the role annotation decl           -- is wrong, just ignore it. We check this in the validity check.@@ -513,7 +514,7 @@         default_roles = build_default_roles argflags role_annots          build_default_roles (argf : argfs) (m_annot : ras)-          | isVisibleArgFlag argf+          | isVisibleForAllTyFlag argf           = (m_annot `orElse` default_role) : build_default_roles argfs ras         build_default_roles (_argf : argfs) ras           = Nominal : build_default_roles argfs ras@@ -902,12 +903,17 @@     con1 = assert (not (null cons_w_field)) $ head cons_w_field      -- Selector type; Note [Polymorphic selectors]-    field_ty   = conLikeFieldType con1 lbl-    data_tvbs  = filter (\tvb -> binderVar tvb `elemVarSet` data_tv_set) $-                 conLikeUserTyVarBinders con1-    data_tv_set= tyCoVarsOfTypes inst_tys+    field_ty    = conLikeFieldType con1 lbl+    data_tv_set = tyCoVarsOfTypes (data_ty : req_theta)+    data_tvbs   = filter (\tvb -> binderVar tvb `elemVarSet` data_tv_set) $+                  conLikeUserTyVarBinders con1++    -- is_naughty: see Note [Naughty record selectors]     is_naughty = not (tyCoVarsOfType field_ty `subVarSet` data_tv_set)-                    || has_sel == NoFieldSelectors+              || has_sel == NoFieldSelectors  -- No field selectors => all are naughty+                                              -- thus suppressing making a binding+                                              -- A slight hack!+     sel_ty | is_naughty = unitTy  -- See Note [Naughty record selectors]            | otherwise  = mkForAllTys (tyVarSpecToBinders data_tvbs) $                           -- Urgh! See Note [The stupid context] in GHC.Core.DataCon@@ -965,23 +971,12 @@         --                 B :: { fld :: Int } -> T Int Char     dealt_with :: ConLike -> Bool     dealt_with (PatSynCon _) = False -- We can't predict overlap-    dealt_with con@(RealDataCon dc) =-      con `elem` cons_w_field || dataConCannotMatch inst_tys dc--    (univ_tvs, _, eq_spec, _, req_theta, _, data_ty) = conLikeFullSig con1+    dealt_with con@(RealDataCon dc)+      = con `elem` cons_w_field || dataConCannotMatch inst_tys dc+      where+        inst_tys = dataConResRepTyArgs dc -    eq_subst = mkTvSubstPrs (map eqSpecPair eq_spec)-    -- inst_tys corresponds to one of the following:-    ---    --  * The arguments to the user-written return type (for GADT constructors).-    --    In this scenario, eq_subst provides a mapping from the universally-    --    quantified type variables to the argument types. Note that eq_subst-    --    does not need to be applied to any other part of the DataCon-    --    (see Note [The dcEqSpec domain invariant] in GHC.Core.DataCon).-    --  * The universally quantified type variables-    --    (for Haskell98-style constructors and pattern synonyms). In these-    --    scenarios, eq_subst is an empty substitution.-    inst_tys = substTyVars eq_subst univ_tvs+    (_, _, _, _, req_theta, _, data_ty) = conLikeFullSig con1      unit_rhs = mkLHsTupleExpr [] noExtField     msg_lit = HsStringPrim NoSourceText (bytesFS (field_label lbl))@@ -1042,9 +1037,28 @@ Hence the sel_naughty flag, to identify record selectors that don't really exist.  In general, a field is "naughty" if its type mentions a type variable that-isn't in the result type of the constructor.  Note that this *allows*-GADT record selectors (Note [GADT record selectors]) whose types may look-like     sel :: T [a] -> a+isn't in+  * the (original, user-written) result type of the constructor, or+  * the "required theta" for the constructor++Note that this *allows* GADT record selectors (Note [GADT record+selectors]) whose types may look like sel :: T [a] -> a++The "required theta" part is illustrated by test patsyn/should_run/records_run+where we have++  pattern ReadP :: Read a => a -> String+  pattern ReadP {readp} <- (read -> readp)++The selector is defined like this:++  $selreadp :: ReadP a => String -> a+  $selReadP s = readp s++Perfectly fine!  The (ReadP a) constraint lets us contructor a value+of type 'a' from a bare String.  NB: "required theta" is empty for+data cons (see conLikeFullSig), so this reasoning only bites for+patttern synonyms.  For naughty selectors we make a dummy binding    sel = ()
compiler/GHC/Tc/Utils/Concrete.hs view
@@ -18,16 +18,16 @@  import GHC.Builtin.Types       ( liftedTypeKindTyCon, unliftedTypeKindTyCon ) -import GHC.Core.Coercion       ( coToMCo, mkCastTyMCo )+import GHC.Core.Coercion       ( coToMCo, mkCastTyMCo+                               , mkGReflRightMCo, mkNomReflCo ) import GHC.Core.TyCo.Rep       ( Type(..), MCoercion(..) ) import GHC.Core.TyCon          ( isConcreteTyCon )-import GHC.Core.Type           ( isConcrete, typeKind, tyVarKind, tcView+import GHC.Core.Type           ( isConcrete, typeKind, tyVarKind, coreView                                , mkTyVarTy, mkTyConApp, mkFunTy, mkAppTy )  import GHC.Tc.Types            ( TcM, ThStage(..), PendingStuff(..) ) import GHC.Tc.Types.Constraint ( NotConcreteError(..), NotConcreteReason(..) )-import GHC.Tc.Types.Evidence   ( Role(..), TcCoercionN, TcMCoercionN-                               , mkTcGReflRightMCo, mkTcNomReflCo )+import GHC.Tc.Types.Evidence   ( Role(..), TcCoercionN, TcMCoercionN ) import GHC.Tc.Types.Origin     ( CtOrigin(..), FixedRuntimeRepContext, FixedRuntimeRepOrigin(..) ) import GHC.Tc.Utils.Monad      ( emitNotConcreteError, setTcLevel, getCtLocM, getStage, traceTc ) import GHC.Tc.Utils.TcType     ( TcType, TcKind, TcTypeFRR@@ -455,12 +455,12 @@           -- Otherwise: ensure that the kind 'ki' of 'ty' is concrete.           | otherwise           -> do { kco <- check_kind frr_orig ki-                ; return ( mkTcGReflRightMCo Nominal ty kco+                ; return ( mkGReflRightMCo Nominal ty kco                          , mkCastTyMCo ty kco ) } }    where     refl :: (TcCoercionN, TcType)-    refl = (mkTcNomReflCo ty, ty)+    refl = (mkNomReflCo ty, ty)     ki :: TcKind     ki = typeKind ty     frr_orig :: FixedRuntimeRepOrigin@@ -634,7 +634,7 @@   where     go :: TcType -> WriterT [NotConcreteReason] TcM TcType     go ty-      | Just ty <- tcView ty+      | Just ty <- coreView ty       = go ty       | isConcrete ty       = pure ty
compiler/GHC/Tc/Utils/Env.hs view
@@ -338,7 +338,7 @@     errNotExact = text "Not an exact match (i.e., some variables get instantiated)"      uniqueTyVars tys = all isTyVarTy tys-                    && hasNoDups (map (getTyVar "tcLookupInstance") tys)+                    && hasNoDups (map getTyVar tys)  tcGetInstEnvs :: TcM InstEnvs -- Gets both the external-package inst-env@@ -684,7 +684,7 @@            ; traceTc "check_then_add_usage" (ppr id_mult $$ ppr actual_u)            ; wrapper <- case actual_u of                Bottom -> return idHsWrapper-               Zero     -> tcSubMult (UsageEnvironmentOf name) Many id_mult+               Zero     -> tcSubMult (UsageEnvironmentOf name) ManyTy id_mult                MUsage m -> do { m <- promote_mult m                               ; tcSubMult (UsageEnvironmentOf name) m id_mult }            ; tcEmitBindingUsage (deleteUE uenv name)
compiler/GHC/Tc/Utils/Instantiate.hs view
@@ -2,7 +2,6 @@ {-# LANGUAGE DisambiguateRecordFields #-}  {-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}-{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}  {- (c) The University of Glasgow 2006@@ -187,7 +186,7 @@       = do { (subst', tvs1) <- tcInstSkolTyVarsX skolem_info subst tvs            ; ev_vars1       <- newEvVars (substTheta subst' theta)            ; go subst'-                (wrap <.> mkWpTyLams tvs1 <.> mkWpLams ev_vars1)+                (wrap <.> mkWpTyLams tvs1 <.> mkWpEvLams ev_vars1)                 (tv_prs ++ (map tyVarName tvs `zip` tvs1))                 (ev_vars ++ ev_vars1)                 inner_ty }@@ -203,7 +202,7 @@ -- NB: returns a type with no (=>), --     and no invisible forall at the top topInstantiate orig sigma-  | (tvs,   body1) <- tcSplitSomeForAllTyVars isInvisibleArgFlag sigma+  | (tvs,   body1) <- tcSplitSomeForAllTyVars isInvisibleForAllTyFlag sigma   , (theta, body2) <- tcSplitPhiTy body1   , not (null tvs && null theta)   = do { (_, wrap1, body3) <- instantiateSigma orig tvs theta body2@@ -261,7 +260,7 @@            ; go (extendTvSubstAndInScope subst tv (ty `mkCastTy` co)) tvs tys }       where         tv_kind = substTy subst (tyVarKind tv)-        ty_kind = tcTypeKind ty+        ty_kind = typeKind ty      go _ _ _ = pprPanic "instTysWith" (ppr tvs $$ ppr tys) @@ -368,6 +367,7 @@  -- | Given ty::forall k1 k2. k, instantiate all the invisible forall-binders --   returning ty @kk1 @kk2 :: k[kk1/k1, kk2/k1]+-- Called only to instantiate kinds, in user-written type signatures tcInstInvisibleTyBinders :: TcType -> TcKind -> TcM (TcType, TcKind) tcInstInvisibleTyBinders ty kind   = do { (extra_args, kind') <- tcInstInvisibleTyBindersN n_invis kind@@ -376,6 +376,7 @@     n_invis = invisibleTyBndrCount kind  tcInstInvisibleTyBindersN :: Int -> TcKind -> TcM ([TcType], TcKind)+-- Called only to instantiate kinds, in user-written type signatures tcInstInvisibleTyBindersN 0 kind   = return ([], kind) tcInstInvisibleTyBindersN n ty@@ -386,27 +387,29 @@     go n subst kind       | n > 0       , Just (bndr, body) <- tcSplitPiTy_maybe kind-      , isInvisibleBinder bndr+      , isInvisiblePiTyBinder bndr       = do { (subst', arg) <- tcInstInvisibleTyBinder subst bndr            ; (args, inner_ty) <- go (n-1) subst' body            ; return (arg:args, inner_ty) }       | otherwise       = return ([], substTy subst kind) --- | Used only in *types*-tcInstInvisibleTyBinder :: Subst -> TyBinder -> TcM (Subst, TcType)+tcInstInvisibleTyBinder :: Subst -> PiTyVarBinder -> TcM (Subst, TcType)+-- Called only to instantiate kinds, in user-written type signatures+ tcInstInvisibleTyBinder subst (Named (Bndr tv _))   = do { (subst', tv') <- newMetaTyVarX subst tv        ; return (subst', mkTyVarTy tv') } -tcInstInvisibleTyBinder subst (Anon af ty)+tcInstInvisibleTyBinder subst (Anon ty af)   | Just (mk, k1, k2) <- get_eq_tys_maybe (substTy subst (scaledThing ty))-    -- Equality is the *only* constraint currently handled in types.+    -- For kinds like (k1 ~ k2) => blah, we want to emit a unification+    -- constraint for (k1 ~# k2) and return the argument (Eq# k1 k2)     -- See Note [Constraints in kinds] in GHC.Core.TyCo.Rep-  = assert (af == InvisArg) $+    -- Equality is the *only* constraint currently handled in types.+  = assert (isInvisibleFunArg af) $     do { co <- unifyKind Nothing k1 k2-       ; arg' <- mk co-       ; return (subst, arg') }+       ; return (subst, mk co) }    | otherwise  -- This should never happen                -- See GHC.Core.TyCo.Rep Note [Constraints in kinds]@@ -414,9 +417,9 @@  ------------------------------- get_eq_tys_maybe :: Type-                 -> Maybe ( Coercion -> TcM Type-                             -- given a coercion proving t1 ~# t2, produce the-                             -- right instantiation for the TyBinder at hand+                 -> Maybe ( Coercion -> Type+                             -- Given a coercion proving t1 ~# t2, produce the+                             -- right instantiation for the PiTyVarBinder at hand                           , Type  -- t1                           , Type  -- t2                           )@@ -425,31 +428,28 @@   -- Lifted heterogeneous equality (~~)   | Just (tc, [_, _, k1, k2]) <- splitTyConApp_maybe ty   , tc `hasKey` heqTyConKey-  = Just (\co -> mkHEqBoxTy co k1 k2, k1, k2)+  = Just (mkHEqBoxTy k1 k2, k1, k2)    -- Lifted homogeneous equality (~)   | Just (tc, [_, k1, k2]) <- splitTyConApp_maybe ty   , tc `hasKey` eqTyConKey-  = Just (\co -> mkEqBoxTy co k1 k2, k1, k2)+  = Just (mkEqBoxTy k1 k2, k1, k2)    | otherwise   = Nothing  -- | This takes @a ~# b@ and returns @a ~~ b@.-mkHEqBoxTy :: TcCoercion -> Type -> Type -> TcM Type--- monadic just for convenience with mkEqBoxTy-mkHEqBoxTy co ty1 ty2-  = return $-    mkTyConApp (promoteDataCon heqDataCon) [k1, k2, ty1, ty2, mkCoercionTy co]-  where k1 = tcTypeKind ty1-        k2 = tcTypeKind ty2+mkHEqBoxTy :: Type -> Type -> TcCoercion -> Type+mkHEqBoxTy ty1 ty2 co+  = mkTyConApp (promoteDataCon heqDataCon) [k1, k2, ty1, ty2, mkCoercionTy co]+  where k1 = typeKind ty1+        k2 = typeKind ty2  -- | This takes @a ~# b@ and returns @a ~ b@.-mkEqBoxTy :: TcCoercion -> Type -> Type -> TcM Type-mkEqBoxTy co ty1 ty2-  = return $-    mkTyConApp (promoteDataCon eqDataCon) [k, ty1, ty2, mkCoercionTy co]-  where k = tcTypeKind ty1+mkEqBoxTy :: Type -> Type -> TcCoercion -> Type+mkEqBoxTy ty1 ty2 co+  = mkTyConApp (promoteDataCon eqDataCon) [k, ty1, ty2, mkCoercionTy co]+  where k = typeKind ty1  {- ********************************************************************* *                                                                      *@@ -488,7 +488,7 @@              subst'  = extendSubstInScopeSet subst (tyCoVarsOfType rho)        ; return (tv_prs, substTheta subst' theta, substTy subst' tau) }   where-    (tyvars, rho) = splitForAllInvisTVBinders poly_ty+    (tyvars, rho) = tcSplitForAllInvisTVBinders poly_ty     (theta, tau)  = tcSplitPhiTy rho      inst_invis_bndr :: Subst -> InvisTVBinder
compiler/GHC/Tc/Utils/Monad.hs view
@@ -4,7 +4,6 @@ {-# LANGUAGE RecordWildCards   #-}  {-# OPTIONS_GHC -fno-warn-orphans #-}-{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}  {- (c) The University of Glasgow 2006@@ -47,7 +46,7 @@   -- * Debugging   traceTc, traceRn, traceOptTcRn, dumpOptTcRn,   dumpTcRn,-  getPrintUnqualified,+  getNamePprCtx,   printForUserTcRn,   traceIf, traceOptIf,   debugTc,@@ -848,11 +847,11 @@ dumpTcRn :: Bool -> DumpFlag -> String -> DumpFormat -> SDoc -> TcRn () dumpTcRn useUserStyle flag title fmt doc = do   logger <- getLogger-  printer <- getPrintUnqualified+  name_ppr_ctx <- getNamePprCtx   real_doc <- wrapDocLoc doc   let sty = if useUserStyle-              then mkUserStyle printer AllTheWay-              else mkDumpStyle printer+              then mkUserStyle name_ppr_ctx AllTheWay+              else mkDumpStyle name_ppr_ctx   liftIO $ logDumpFile logger sty flag title fmt real_doc  -- | Add current location if -dppr-debug@@ -867,18 +866,19 @@     else       return doc -getPrintUnqualified :: TcRn PrintUnqualified-getPrintUnqualified-  = do { rdr_env <- getGlobalRdrEnv+getNamePprCtx :: TcRn NamePprCtx+getNamePprCtx+  = do { ptc <- initPromotionTickContext <$> getDynFlags+       ; rdr_env <- getGlobalRdrEnv        ; hsc_env <- getTopEnv-       ; return $ mkPrintUnqualified (hsc_unit_env hsc_env) rdr_env }+       ; return $ mkNamePprCtx ptc (hsc_unit_env hsc_env) rdr_env }  -- | Like logInfoTcRn, but for user consumption printForUserTcRn :: SDoc -> TcRn () printForUserTcRn doc = do     logger <- getLogger-    printer <- getPrintUnqualified-    liftIO (printOutputForUser logger printer doc)+    name_ppr_ctx <- getNamePprCtx+    liftIO (printOutputForUser logger name_ppr_ctx doc)  {- traceIf works in the TcRnIf monad, where no RdrEnv is@@ -1118,9 +1118,9 @@   where     mk_long_err_at :: SrcSpan -> TcRnMessageDetailed -> TcRn (MsgEnvelope TcRnMessage)     mk_long_err_at loc msg-      = do { printer <- getPrintUnqualified ;+      = do { name_ppr_ctx <- getNamePprCtx ;              unit_state <- hsc_units <$> getTopEnv ;-             return $ mkErrorMsgEnvelope loc printer+             return $ mkErrorMsgEnvelope loc name_ppr_ctx                     $ TcRnMessageWithInfo unit_state msg                     } @@ -1128,9 +1128,9 @@               -> TcRnMessage               -> TcRn (MsgEnvelope TcRnMessage) mkTcRnMessage loc msg-  = do { printer <- getPrintUnqualified ;+  = do { name_ppr_ctx <- getNamePprCtx ;          diag_opts <- initDiagOpts <$> getDynFlags ;-         return $ mkMsgEnvelope diag_opts loc printer msg }+         return $ mkMsgEnvelope diag_opts loc name_ppr_ctx msg }  reportDiagnostics :: [MsgEnvelope TcRnMessage] -> TcM () reportDiagnostics = mapM_ reportDiagnostic@@ -1614,12 +1614,12 @@ addDetailedDiagnostic :: (ErrInfo -> TcRnMessage) -> TcM () addDetailedDiagnostic mkMsg = do   loc <- getSrcSpanM-  printer <- getPrintUnqualified+  name_ppr_ctx <- getNamePprCtx   !diag_opts  <- initDiagOpts <$> getDynFlags   env0 <- tcInitTidyEnv   ctxt <- getErrCtxt   err_info <- mkErrInfo env0 ctxt-  reportDiagnostic (mkMsgEnvelope diag_opts loc printer (mkMsg (ErrInfo err_info empty)))+  reportDiagnostic (mkMsgEnvelope diag_opts loc name_ppr_ctx (mkMsg (ErrInfo err_info empty)))  addTcRnDiagnostic :: TcRnMessage -> TcM () addTcRnDiagnostic msg = do@@ -1921,7 +1921,7 @@                          , hole_loc  = ct_loc }        ; emitHole hole }   where-    occ = mkTyVarOcc "_"+    occ = mkTyVarOccFS (fsLit "_")     sort | YesExtraConstraint <- extra_constraints = ConstraintHole          | otherwise                               = TypeHole 
compiler/GHC/Tc/Utils/TcMType.hs view
@@ -111,9 +111,9 @@ import qualified GHC.LanguageExtensions as LangExt  import GHC.Tc.Types.Origin-import GHC.Tc.Utils.Monad        -- TcType, amongst others import GHC.Tc.Types.Constraint import GHC.Tc.Types.Evidence+import GHC.Tc.Utils.Monad        -- TcType, amongst others import GHC.Tc.Utils.TcType import GHC.Tc.Errors.Types import GHC.Tc.Errors.Ppr@@ -149,7 +149,6 @@ import GHC.Utils.Panic import GHC.Utils.Panic.Plain import GHC.Utils.Constants (debugIsOn)-import GHC.Utils.Trace  import Control.Monad import GHC.Data.Maybe@@ -192,7 +191,7 @@ newEvVar :: TcPredType -> TcRnIf gbl lcl EvVar -- Creates new *rigid* variables for predicates newEvVar ty = do { name <- newSysName (predTypeOccName ty)-                 ; return (mkLocalIdOrCoVar name Many ty) }+                 ; return (mkLocalIdOrCoVar name ManyTy ty) }  -- | Create a new Wanted constraint with the given 'CtLoc'. newWantedWithLoc :: CtLoc -> PredType -> TcM CtEvidence@@ -320,7 +319,7 @@ newDict :: Class -> [TcType] -> TcM DictId newDict cls tys   = do { name <- newSysName (mkDictOcc (getOccName cls))-       ; return (mkLocalId name Many (mkClassPred cls tys)) }+       ; return (mkLocalId name ManyTy (mkClassPred cls tys)) }  predTypeOccName :: PredType -> OccName predTypeOccName ty = case classifyPredType ty of@@ -644,7 +643,7 @@ promoteTcType dest_lvl ty   = do { cur_lvl <- getTcLevel        ; if (cur_lvl `sameDepthAs` dest_lvl)-         then return (mkTcNomReflCo ty, ty)+         then return (mkNomReflCo ty, ty)          else promote_it }   where     promote_it :: TcM (TcCoercion, TcType)@@ -972,13 +971,11 @@        -- Zonk kinds to allow the error check to work        ; zonked_tv_kind <- zonkTcType tv_kind        ; zonked_ty      <- zonkTcType ty-       ; let zonked_ty_kind = tcTypeKind zonked_ty+       ; let zonked_ty_kind = typeKind zonked_ty              zonked_ty_lvl  = tcTypeLevel zonked_ty              level_check_ok  = not (zonked_ty_lvl `strictlyDeeperThan` tv_lvl)              level_check_msg = ppr zonked_ty_lvl $$ ppr tv_lvl $$ ppr tyvar $$ ppr ty              kind_check_ok = zonked_ty_kind `eqType` zonked_tv_kind-             -- Hack alert! eqType, not tcEqType. see:-             -- Note [coreView vs tcView] in GHC.Core.Type              -- Note [Extra-constraint holes in partial type signatures] in GHC.Tc.Gen.HsType               kind_msg = hang (text "Ill-kinded update to meta tyvar")@@ -1502,24 +1499,24 @@                      -> TcM CandidatesQTvs collect_cand_qtvs_co orig_ty bound = go_co   where-    go_co dv (Refl ty)             = collect_cand_qtvs orig_ty True bound dv ty-    go_co dv (GRefl _ ty mco)      = do dv1 <- collect_cand_qtvs orig_ty True bound dv ty-                                        go_mco dv1 mco-    go_co dv (TyConAppCo _ _ cos)  = foldlM go_co dv cos-    go_co dv (AppCo co1 co2)       = foldlM go_co dv [co1, co2]-    go_co dv (FunCo _ w co1 co2)   = foldlM go_co dv [w, co1, co2]-    go_co dv (AxiomInstCo _ _ cos) = foldlM go_co dv cos-    go_co dv (AxiomRuleCo _ cos)   = foldlM go_co dv cos-    go_co dv (UnivCo prov _ t1 t2) = do dv1 <- go_prov dv prov-                                        dv2 <- collect_cand_qtvs orig_ty True bound dv1 t1-                                        collect_cand_qtvs orig_ty True bound dv2 t2-    go_co dv (SymCo co)            = go_co dv co-    go_co dv (TransCo co1 co2)     = foldlM go_co dv [co1, co2]-    go_co dv (NthCo _ _ co)        = go_co dv co-    go_co dv (LRCo _ co)           = go_co dv co-    go_co dv (InstCo co1 co2)      = foldlM go_co dv [co1, co2]-    go_co dv (KindCo co)           = go_co dv co-    go_co dv (SubCo co)            = go_co dv co+    go_co dv (Refl ty)               = collect_cand_qtvs orig_ty True bound dv ty+    go_co dv (GRefl _ ty mco)        = do dv1 <- collect_cand_qtvs orig_ty True bound dv ty+                                          go_mco dv1 mco+    go_co dv (TyConAppCo _ _ cos)    = foldlM go_co dv cos+    go_co dv (AppCo co1 co2)         = foldlM go_co dv [co1, co2]+    go_co dv (FunCo _ _ _ w co1 co2) = foldlM go_co dv [w, co1, co2]+    go_co dv (AxiomInstCo _ _ cos)   = foldlM go_co dv cos+    go_co dv (AxiomRuleCo _ cos)     = foldlM go_co dv cos+    go_co dv (UnivCo prov _ t1 t2)   = do dv1 <- go_prov dv prov+                                          dv2 <- collect_cand_qtvs orig_ty True bound dv1 t1+                                          collect_cand_qtvs orig_ty True bound dv2 t2+    go_co dv (SymCo co)              = go_co dv co+    go_co dv (TransCo co1 co2)       = foldlM go_co dv [co1, co2]+    go_co dv (SelCo _ co)            = go_co dv co+    go_co dv (LRCo _ co)             = go_co dv co+    go_co dv (InstCo co1 co2)        = foldlM go_co dv [co1, co2]+    go_co dv (KindCo co)             = go_co dv co+    go_co dv (SubCo co)              = go_co dv co      go_co dv (HoleCo hole)       = do m_co <- unpackCoercionHole_maybe hole@@ -2521,7 +2518,7 @@ zonkTcTyVarToTcTyVar :: HasDebugCallStack => TcTyVar -> TcM TcTyVar zonkTcTyVarToTcTyVar tv   = do { ty <- zonkTcTyVar tv-       ; let tv' = case tcGetTyVar_maybe ty of+       ; let tv' = case getTyVar_maybe ty of                      Just tv' -> tv'                      Nothing  -> pprPanic "zonkTcTyVarToTcTyVar"                                           (ppr tv $$ ppr ty)
compiler/GHC/Tc/Utils/Unify.hs view
@@ -2,9 +2,6 @@ {-# LANGUAGE TupleSections       #-} {-# LANGUAGE RecursiveDo         #-} -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}-{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}- {- (c) The University of Glasgow 2006 (c) The GRASP/AQUA Project, Glasgow University, 1992-1998@@ -42,8 +39,7 @@ import GHC.Prelude  import GHC.Hs-import GHC.Core.TyCo.Rep-import GHC.Core.TyCo.Ppr( debugPprType )+ import GHC.Tc.Utils.Concrete ( hasFixedRuntimeRep, makeTypeConcrete, hasFixedRuntimeRep_syntactic ) import GHC.Tc.Utils.Env import GHC.Tc.Utils.Instantiate@@ -52,6 +48,9 @@ import GHC.Tc.Utils.TcType  import GHC.Core.Type+import GHC.Core.TyCo.Rep+import GHC.Core.TyCo.Ppr( debugPprType )+import GHC.Core.TyCon import GHC.Core.Coercion import GHC.Core.Multiplicity @@ -62,7 +61,6 @@ import GHC.Tc.Types.Origin import GHC.Types.Name( Name, isSystemName ) -import GHC.Core.TyCon import GHC.Builtin.Types import GHC.Types.Var as Var import GHC.Types.Var.Set@@ -132,10 +130,10 @@     go :: TcRhoType   -- The type we're processing, perhaps after                       -- expanding type synonyms        -> TcM (HsWrapper, Scaled TcSigmaTypeFRR, TcSigmaType)-    go ty | Just ty' <- tcView ty = go ty'+    go ty | Just ty' <- coreView ty = go ty'      go (FunTy { ft_af = af, ft_mult = w, ft_arg = arg_ty, ft_res = res_ty })-      = assert (af == VisArg) $+      = assert (isVisibleFunArg af) $       do { hasFixedRuntimeRep_syntactic (FRRExpectedFunTy herald 1) arg_ty          ; return (idHsWrapper, Scaled w arg_ty, res_ty) } @@ -168,7 +166,7 @@       = do { arg_ty <- newOpenFlexiTyVarTy            ; res_ty <- newOpenFlexiTyVarTy            ; mult <- newFlexiTyVarTy multiplicityTy-           ; let unif_fun_ty = mkVisFunTy mult arg_ty res_ty+           ; let unif_fun_ty = tcMkVisFunTy mult arg_ty res_ty            ; co <- unifyType mb_thing fun_ty unif_fun_ty            ; hasFixedRuntimeRep_syntactic (FRRExpectedFunTy herald 1) arg_ty            ; return (mkWpCastN co, Scaled mult arg_ty, res_ty) }@@ -387,17 +385,17 @@                                                go acc_arg_tys n ty'            ; return (wrap_gen <.> wrap_res, result) } -    -- No more args; do this /before/ tcView, so+    -- No more args; do this /before/ coreView, so     -- that we do not unnecessarily unwrap synonyms     go acc_arg_tys 0 rho_ty       = do { result <- thing_inside (reverse acc_arg_tys) (mkCheckExpType rho_ty)            ; return (idHsWrapper, result) }      go acc_arg_tys n ty-      | Just ty' <- tcView ty = go acc_arg_tys n ty'+      | Just ty' <- coreView ty = go acc_arg_tys n ty' -    go acc_arg_tys n (FunTy { ft_mult = mult, ft_af = af, ft_arg = arg_ty, ft_res = res_ty })-      = assert (af == VisArg) $+    go acc_arg_tys n (FunTy { ft_af = af, ft_mult = mult, ft_arg = arg_ty, ft_res = res_ty })+      = assert (isVisibleFunArg af) $         do { let arg_pos = 1 + length acc_arg_tys -- for error messages only            ; (arg_co, arg_ty) <- hasFixedRuntimeRep (FRRExpectedFunTy herald arg_pos) arg_ty            ; (wrap_res, result) <- go ((Scaled mult $ mkCheckExpType arg_ty) : acc_arg_tys)@@ -440,7 +438,7 @@            ; result       <- thing_inside (reverse acc_arg_tys ++ more_arg_tys) res_ty            ; more_arg_tys <- mapM (\(Scaled m t) -> Scaled m <$> readExpType t) more_arg_tys            ; res_ty       <- readExpType res_ty-           ; let unif_fun_ty = mkVisFunTys more_arg_tys res_ty+           ; let unif_fun_ty = mkScaledFunTys more_arg_tys res_ty            ; wrap <- tcSubType AppOrigin ctx unif_fun_ty fun_ty                          -- Not a good origin at all :-(            ; return (wrap, result) }@@ -465,7 +463,7 @@             -> TcM (TidyEnv, SDoc) mkFunTysMsg env herald arg_tys res_ty n_val_args_in_call   = do { (env', fun_rho) <- zonkTidyTcType env $-                            mkVisFunTys arg_tys res_ty+                            mkScaledFunTys arg_tys res_ty         ; let (all_arg_tys, _) = splitFunTys fun_rho              n_fun_args = length all_arg_tys@@ -502,15 +500,16 @@ -- Postcondition: (T k1 k2 k3 a b c) is well-kinded  matchExpectedTyConApp tc orig_ty-  = assert (not $ isFunTyCon tc) $ go orig_ty+  = assertPpr (isAlgTyCon tc) (ppr tc) $+    go orig_ty   where     go ty-       | Just ty' <- tcView ty+       | Just ty' <- coreView ty        = go ty'      go ty@(TyConApp tycon args)        | tc == tycon  -- Common case-       = return (mkTcNomReflCo ty, args)+       = return (mkNomReflCo ty, args)      go (TyVarTy tv)        | isMetaTyVar tv@@ -550,10 +549,10 @@   = go orig_ty   where     go ty-      | Just ty' <- tcView ty = go ty'+      | Just ty' <- coreView ty = go ty'        | Just (fun_ty, arg_ty) <- tcSplitAppTy_maybe ty-      = return (mkTcNomReflCo orig_ty, (fun_ty, arg_ty))+      = return (mkNomReflCo orig_ty, (fun_ty, arg_ty))      go (TyVarTy tv)       | isMetaTyVar tv@@ -571,7 +570,7 @@            ; co <- unifyType Nothing (mkAppTy ty1 ty2) orig_ty            ; return (co, (ty1, ty2)) } -    orig_kind = tcTypeKind orig_ty+    orig_kind = typeKind orig_ty     kind1 = mkVisFunTyMany liftedTypeKind orig_kind     kind2 = liftedTypeKind    -- m :: * -> k                               -- arg type :: *@@ -651,7 +650,7 @@                            Just frr_orig -> hasFixedRuntimeRep frr_orig act_res_ty                       -- Compose the two coercions.-                     ; let final_co = prom_co `mkTcTransCo` frr_co+                     ; let final_co = prom_co `mkTransCo` frr_co                       ; writeTcRef ref (Just act_res_ty) @@ -840,7 +839,7 @@   = do { co <- fillInferResult ty_expected inf_res                -- In patterns we do not instantatiate -       ; return (mkWpCastN (mkTcSymCo co)) }+       ; return (mkWpCastN (mkSymCo co)) }  --------------- tcSubType :: CtOrigin -> UserTypeCtxt@@ -1278,9 +1277,9 @@               , text "ty_expected =" <+> ppr ty_expected ]        ; go ty_actual ty_expected }   where-    -- NB: 'go' is not recursive, except for doing tcView-    go ty_a ty_e | Just ty_a' <- tcView ty_a = go ty_a' ty_e-                 | Just ty_e' <- tcView ty_e = go ty_a  ty_e'+    -- NB: 'go' is not recursive, except for doing coreView+    go ty_a ty_e | Just ty_a' <- coreView ty_a = go ty_a' ty_e+                 | Just ty_e' <- coreView ty_e = go ty_a  ty_e'      go (TyVarTy tv_a) ty_e       = do { lookup_res <- isFilledMetaTyVar_maybe tv_a@@ -1291,13 +1290,13 @@                     ; tc_sub_type_ds unify inst_orig ctxt ty_a' ty_e }                Nothing -> just_unify ty_actual ty_expected } -    go ty_a@(FunTy { ft_af = VisArg, ft_mult = act_mult, ft_arg = act_arg, ft_res = act_res })-       ty_e@(FunTy { ft_af = VisArg, ft_mult = exp_mult, ft_arg = exp_arg, ft_res = exp_res })-      | isTauTy ty_a, isTauTy ty_e         -- Short cut common case to avoid-      = just_unify ty_actual ty_expected   -- unnecessary eta expansion--      | otherwise-      = -- This is where we do the co/contra thing, and generate a WpFun, which in turn+    go ty_a@(FunTy { ft_af = af1, ft_mult = act_mult, ft_arg = act_arg, ft_res = act_res })+       ty_e@(FunTy { ft_af = af2, ft_mult = exp_mult, ft_arg = exp_arg, ft_res = exp_res })+      | isVisibleFunArg af1, isVisibleFunArg af2+      = if (isTauTy ty_a && isTauTy ty_e)       -- Short cut common case to avoid+        then just_unify ty_actual ty_expected   -- unnecessary eta expansion+        else+        -- This is where we do the co/contra thing, and generate a WpFun, which in turn         -- causes eta-expansion, which we don't like; hence encouraging NoDeepSubsumption         do { arg_wrap  <- tc_sub_type_deep unify given_orig GenSigCtxt exp_arg act_arg                           -- GenSigCtxt: See Note [Setting the argument context]@@ -1380,14 +1379,12 @@            ; ev_vars1       <- newEvVars (substTheta subst' theta)            ; (wrap, tvs_prs2, ev_vars2, rho) <- go subst' ty'            ; let tv_prs1 = map tyVarName tvs `zip` tvs1-           ; return ( mkWpLams ids1-                      <.> mkWpTyLams tvs1-                      <.> mkWpLams ev_vars1-                      <.> wrap-                      <.> mkWpEvVarApps ids1+           ; return ( mkWpEta ids1 (mkWpTyLams tvs1+                                    <.> mkWpEvLams ev_vars1+                                    <.> wrap)                     , tv_prs1  ++ tvs_prs2                     , ev_vars1 ++ ev_vars2-                    , mkVisFunTys arg_tys' rho ) }+                    , mkScaledFunTys arg_tys' rho ) }        | otherwise       = return (idHsWrapper, [], [], substTy subst ty)@@ -1407,11 +1404,8 @@            ; ids1  <- newSysLocalIds (fsLit "di") arg_tys'            ; wrap1 <- instCall orig (mkTyVarTys tvs') theta'            ; (wrap2, rho2) <- go subst' rho-           ; return (mkWpLams ids1-                        <.> wrap2-                        <.> wrap1-                        <.> mkWpEvVarApps ids1,-                     mkVisFunTys arg_tys' rho2) }+           ; return (mkWpEta ids1 (wrap2 <.> wrap1),+                     mkScaledFunTys arg_tys' rho2) }        | otherwise       = do { let ty' = substTy subst ty@@ -1703,7 +1697,7 @@ -}  unifyType :: Maybe TypedThing  -- ^ If present, the thing that has type ty1-          -> TcTauType -> TcTauType    -- ty1, ty2+          -> TcTauType -> TcTauType    -- ty1 (actual), ty2 (expected)           -> TcM TcCoercionN           -- :: ty1 ~# ty2 -- Actual and expected types -- Returns a coercion : ty1 ~ ty2@@ -1757,6 +1751,8 @@ -------------- -- It is always safe to defer unification to the main constraint solver -- See Note [Deferred unification]+--    ty1 is "actual"+--    ty2 is "expected" uType_defer t_or_k origin ty1 ty2   = do { co <- emitWantedEq origin t_or_k Nominal ty1 ty2 @@ -1833,17 +1829,18 @@         -- we'll end up saying "can't match Foo with Bool"         -- rather than "can't match "Int with Bool".  See #4535.     go ty1 ty2-      | Just ty1' <- tcView ty1 = go ty1' ty2-      | Just ty2' <- tcView ty2 = go ty1  ty2'+      | Just ty1' <- coreView ty1 = go ty1' ty2+      | Just ty2' <- coreView ty2 = go ty1  ty2'      -- Functions (t1 -> t2) just check the two parts     -- Do not attempt (c => t); just defer-    go (FunTy { ft_af = VisArg, ft_mult = w1, ft_arg = arg1, ft_res = res1 })-       (FunTy { ft_af = VisArg, ft_mult = w2, ft_arg = arg2, ft_res = res2 })+    go (FunTy { ft_af = af1, ft_mult = w1, ft_arg = arg1, ft_res = res1 })+       (FunTy { ft_af = af2, ft_mult = w2, ft_arg = arg2, ft_res = res2 })+      | isVisibleFunArg af1, af1 == af2       = do { co_l <- uType t_or_k origin arg1 arg2            ; co_r <- uType t_or_k origin res1 res2            ; co_w <- uType t_or_k origin w1 w2-           ; return $ mkFunCo Nominal co_w co_l co_r }+           ; return $ mkNakedFunCo1 Nominal af1 co_w co_l co_r }          -- Always defer if a type synonym family (type function)         -- is involved.  (Data families behave rigidly.)@@ -1874,12 +1871,12 @@      go (AppTy s1 t1) (TyConApp tc2 ts2)       | Just (ts2', t2') <- snocView ts2-      = assert (not (mustBeSaturated tc2)) $+      = assert (not (tyConMustBeSaturated tc2)) $         go_app (isNextTyConArgVisible tc2 ts2') s1 t1 (TyConApp tc2 ts2') t2'      go (TyConApp tc1 ts1) (AppTy s2 t2)       | Just (ts1', t1') <- snocView ts1-      = assert (not (mustBeSaturated tc1)) $+      = assert (not (tyConMustBeSaturated tc1)) $         go_app (isNextTyConArgVisible tc1 ts1') (TyConApp tc1 ts1') t1' s2 t2      go (CoercionTy co1) (CoercionTy co2)@@ -2030,7 +2027,7 @@               -> TcTauType      -- Type 2, zonked               -> TcM Coercion uUnfilledVar1 origin t_or_k swapped tv1 ty2-  | Just tv2 <- tcGetTyVar_maybe ty2+  | Just tv2 <- getTyVar_maybe ty2   = go tv2    | otherwise@@ -2077,18 +2074,18 @@            ; if not can_continue_solving              then not_ok_so_defer              else-        do { co_k <- uType KindLevel kind_origin (tcTypeKind ty2) (tyVarKind tv1)+        do { co_k <- uType KindLevel kind_origin (typeKind ty2) (tyVarKind tv1)            ; traceTc "uUnfilledVar2 ok" $              vcat [ ppr tv1 <+> dcolon <+> ppr (tyVarKind tv1)-                  , ppr ty2 <+> dcolon <+> ppr (tcTypeKind  ty2)-                  , ppr (isTcReflCo co_k), ppr co_k ]+                  , ppr ty2 <+> dcolon <+> ppr (typeKind  ty2)+                  , ppr (isReflCo co_k), ppr co_k ] -           ; if isTcReflCo co_k+           ; if isReflCo co_k                -- Only proceed if the kinds match                -- NB: tv1 should still be unfilled, despite the kind unification                --     because tv1 is not free in ty2 (or, hence, in its kind)              then do { writeMetaTyVar tv1 ty2-                     ; return (mkTcNomReflCo ty2) }+                     ; return (mkNomReflCo ty2) }               else defer }} -- This cannot be solved now.  See GHC.Tc.Solver.Canonical                            -- Note [Equalities with incompatible kinds] for how@@ -2134,7 +2131,7 @@                [] -> return True                _  -> return False }       TyVarTv ->-        case tcGetTyVar_maybe xi of+        case getTyVar_maybe xi of            Nothing -> return False            Just tv ->              case tcTyVarDetails tv of -- (TYVAR-TV) wrinkle@@ -2310,6 +2307,9 @@  Note [TyVar/TyVar orientation] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See also Note [Fundeps with instances, and equality orientation]+where the kind equality orientation is important+ Given (a ~ b), should we orient the CEqCan as (a~b) or (b~a)? This is a surprisingly tricky question! This is invariant (TyEq:TV). @@ -2516,14 +2516,14 @@ matchExpectedFunKind   :: TypedThing     -- ^ type, only for errors   -> Arity           -- ^ n: number of desired arrows-  -> TcKind          -- ^ fun_ kind+  -> TcKind          -- ^ fun_kind   -> TcM Coercion    -- ^ co :: fun_kind ~ (arg1 -> ... -> argn -> res)  matchExpectedFunKind hs_ty n k = go n k   where     go 0 k = return (mkNomReflCo k) -    go n k | Just k' <- tcView k = go n k'+    go n k | Just k' <- coreView k = go n k'      go n k@(TyVarTy kvar)       | isMetaTyVar kvar@@ -2532,9 +2532,10 @@                 Indirect fun_kind -> go n fun_kind                 Flexi ->             defer n k } -    go n (FunTy { ft_mult = w, ft_arg = arg, ft_res = res })+    go n (FunTy { ft_af = af, ft_mult = w, ft_arg = arg, ft_res = res })+      | isVisibleFunArg af       = do { co <- go (n-1) res-           ; return (mkTcFunCo Nominal (mkTcNomReflCo w) (mkTcNomReflCo arg) co) }+           ; return (mkNakedFunCo1 Nominal af (mkNomReflCo w) (mkNomReflCo arg) co) }      go n other      = defer n other@@ -2658,7 +2659,7 @@     go (LitTy {})              = cteOK     go (FunTy {ft_af = af, ft_mult = w, ft_arg = a, ft_res = r})                                = go w S.<> go a S.<> go r S.<>-                                 if not ghci_tv && af == InvisArg+                                 if not ghci_tv && isInvisibleFunArg af                                    then impredicative                                    else cteOK     go (AppTy fun arg) = go fun S.<> go arg
compiler/GHC/Tc/Utils/Zonk.hs view
@@ -57,7 +57,7 @@ import GHC.Tc.Utils.Env   ( tcLookupGlobalOnly ) import GHC.Tc.Types.Evidence -import GHC.Core.TyCo.Ppr ( pprTyVar )+import GHC.Core.TyCo.Ppr     ( pprTyVar ) import GHC.Core.TyCon import GHC.Core.Type import GHC.Core.Coercion@@ -1009,7 +1009,7 @@        new_ty <- zonkTcTypeToTypeX env ty        new_ids <- mapSndM (zonkExpr env) ids -       massert (isLiftedTypeKind (tcTypeKind new_stack_tys))+       massert (isLiftedTypeKind (typeKind new_stack_tys))          -- desugarer assumes that this is not representation-polymorphic...          -- but indeed it should always be lifted due to the typing          -- rules for arrows@@ -1634,7 +1634,7 @@         ; term' <- case getEqPredTys_maybe (idType var') of            Just (r, ty1, ty2) | ty1 `eqType` ty2-                  -> return (evCoercion (mkTcReflCo r ty1))+                  -> return (evCoercion (mkReflCo r ty1))            _other -> zonkEvTerm env term         ; return (bind { eb_lhs = var', eb_rhs = term' }) }
compiler/GHC/Tc/Validity.hs view
@@ -21,6 +21,7 @@   ) where  import GHC.Prelude+import GHC.Data.FastString  import GHC.Data.Maybe @@ -366,7 +367,7 @@ --    that is, checkValidType doesn't need to do kind checking -- Not used for instance decls; checkValidInstance instead checkValidType ctxt ty-  = do { traceTc "checkValidType" (ppr ty <+> text "::" <+> ppr (tcTypeKind ty))+  = do { traceTc "checkValidType" (ppr ty <+> text "::" <+> ppr (typeKind ty))        ; rankn_flag  <- xoptM LangExt.RankNTypes        ; impred_flag <- xoptM LangExt.ImpredicativeTypes        ; let gen_rank :: Rank -> Rank@@ -432,7 +433,7 @@        --     and there may be nested foralls for the subtype test to examine        ; checkAmbiguity ctxt ty -       ; traceTc "checkValidType done" (ppr ty <+> text "::" <+> ppr (tcTypeKind ty)) }+       ; traceTc "checkValidType done" (ppr ty <+> text "::" <+> ppr (typeKind ty)) }  checkValidMonoType :: Type -> TcM () -- Assumes argument is fully zonked@@ -445,10 +446,10 @@  checkTySynRhs :: UserTypeCtxt -> TcType -> TcM () checkTySynRhs ctxt ty-  | tcReturnsConstraintKind actual_kind+  | returnsConstraintKind actual_kind   = do { ck <- xoptM LangExt.ConstraintKinds        ; if ck-         then  when (tcIsConstraintKind actual_kind)+         then  when (isConstraintLikeKind actual_kind)                     (do { dflags <- getDynFlags                         ; expand <- initialExpandMode                         ; check_pred_ty emptyTidyEnv dflags ctxt expand ty })@@ -459,7 +460,7 @@   | otherwise   = return ()   where-    actual_kind = tcTypeKind ty+    actual_kind = typeKind ty  funArgResRank :: Rank -> (Rank, Rank)             -- Function argument and result funArgResRank (LimitedRank _ arg_rank) = (arg_rank, LimitedRank (forAllAllowed arg_rank) arg_rank)@@ -760,12 +761,12 @@   where     (tvbs, phi)   = tcSplitForAllTyVarBinders ty     (theta, tau)  = tcSplitPhiTy phi-    (env', _)     = tidyTyCoVarBinders env tvbs+    (env', _)     = tidyForAllTyBinders env tvbs  check_type (ve@ValidityEnv{ ve_tidy_env = env, ve_ctxt = ctxt                           , ve_rank = rank })            ty@(FunTy _ mult arg_ty res_ty)-  = do  { failIfTcM (not (linearityAllowed ctxt) && not (isManyDataConTy mult))+  = do  { failIfTcM (not (linearityAllowed ctxt) && not (isManyTy mult))                      (env, TcRnLinearFuncInKind (tidyType env ty))         ; check_type (ve{ve_rank = arg_rank}) arg_ty         ; check_type (ve{ve_rank = res_rank}) res_ty }@@ -817,7 +818,7 @@      check_expansion_only expand       = assertPpr (isTypeSynonymTyCon tc) (ppr tc) $-        case tcView ty of+        case coreView ty of          Just ty' -> let err_ctxt = text "In the expansion of type synonym"                                     <+> quotes (ppr tc)                      in addErrCtxt err_ctxt $@@ -941,7 +942,7 @@   checkTcM (vdqAllowed ctxt || no_vdq)            (env, TcRnVDQInTermType (Just (tidyType env ty)))   where-    no_vdq = all (isInvisibleArgFlag . binderArgFlag) tvbs+    no_vdq = all (isInvisibleForAllTyFlag . binderFlag) tvbs     ValidityEnv{ve_tidy_env = env, ve_ctxt = ctxt} = ve  {-@@ -1085,7 +1086,7 @@                 -> DynFlags -> UserTypeCtxt                 -> PredType -> TcM () check_pred_help under_syn env dflags ctxt pred-  | Just pred' <- tcView pred  -- Switch on under_syn when going under a+  | Just pred' <- coreView pred  -- Switch on under_syn when going under a                                  -- synonym (#9838, yuk)   = check_pred_help True env dflags ctxt pred' @@ -1544,7 +1545,9 @@ tcInstHeadTyAppAllTyVars ty   | Just (tc, tys) <- tcSplitTyConApp_maybe (dropCasts ty)   = let tys' = filterOutInvisibleTypes tc tys  -- avoid kinds-        tys'' | tc == funTyCon, tys_h:tys_t <- tys', tys_h `eqType` manyDataConTy = tys_t+        tys'' | tc `hasKey` fUNTyConKey+              , ManyTy : tys_t <- tys'+              = tys_t               | otherwise = tys'     in ok tys''   | LitTy _ <- ty = True  -- accept type literals (#13833)@@ -1555,7 +1558,7 @@         -- and that each is distinct     ok tys = equalLength tvs tys && hasNoDups tvs            where-             tvs = mapMaybe tcGetTyVar_maybe tys+             tvs = mapMaybe getTyVar_maybe tys  dropCasts :: Type -> Type -- See Note [Casts during validity checking]@@ -1731,15 +1734,12 @@ -}  checkValidInstance :: UserTypeCtxt -> LHsSigType GhcRn -> Type -> TcM ()-checkValidInstance ctxt hs_type ty-  | not is_tc_app-  = failWithTc (TcRnNoClassInstHead tau)--  | isNothing mb_cls-  = failWithTc (TcRnIllegalClassInst (tyConFlavour tc))--  | otherwise-  = do  { setSrcSpanA head_loc $+checkValidInstance ctxt hs_type ty = case tau of+  -- See Note [Instances and constraint synonyms]+  TyConApp tc inst_tys -> case tyConClass_maybe tc of+    Nothing -> failWithTc (TcRnIllegalClassInst (tyConFlavour tc))+    Just clas -> do+        { setSrcSpanA head_loc $           checkValidInstHead ctxt clas inst_tys          ; traceTc "checkValidInstance {" (ppr ty)@@ -1772,12 +1772,9 @@         ; traceTc "End checkValidInstance }" empty          ; return () }+  _ -> failWithTc (TcRnNoClassInstHead tau)   where     (_tvs, theta, tau)   = tcSplitSigmaTy ty-    is_tc_app            = case tau of { TyConApp {} -> True; _ -> False }-    TyConApp tc inst_tys = tau   -- See Note [Instances and constraint synonyms]-    mb_cls               = tyConClass_maybe tc-    Just clas            = mb_cls          -- The location of the "head" of the instance     head_loc = getLoc (getLHsInstDeclHead hs_type)@@ -2026,23 +2023,23 @@   do { cpt_tvs <- zipWithM extract_tv pats pats_vis      ; check_all_distinct_tvs $ zip cpt_tvs pats_vis }   where-    pats_vis :: [ArgFlag]-    pats_vis = tyConArgFlags fam_tc pats+    pats_vis :: [ForAllTyFlag]+    pats_vis = tyConForAllTyFlags fam_tc pats      -- Checks that a pattern on the LHS of a default is a type     -- variable. If so, return the underlying type variable, and if     -- not, throw an error.     -- See Note [Type-checking default assoc decls]-    extract_tv :: Type    -- The particular type pattern from which to extract-                          -- its underlying type variable-               -> ArgFlag -- The visibility of the type pattern-                          -- (only used for error message purposes)+    extract_tv :: Type          -- The particular type pattern from which to+                                -- extrace its underlying type variable+               -> ForAllTyFlag  -- The visibility of the type pattern+                                -- (only used for error message purposes)                -> TcM TyVar     extract_tv pat pat_vis =       case getTyVar_maybe pat of         Just tv -> pure tv         Nothing -> failWithTc $ mkTcRnUnknownMessage $ mkPlainError noHints $-          pprWithExplicitKindsWhen (isInvisibleArgFlag pat_vis) $+          pprWithExplicitKindsWhen (isInvisibleForAllTyFlag pat_vis) $           hang (text "Illegal argument" <+> quotes (ppr pat) <+> text "in:")              2 (vcat [ppr_eqn, suggestion]) @@ -2050,7 +2047,7 @@     -- duplicated. If that is the case, throw an error.     -- See Note [Type-checking default assoc decls]     check_all_distinct_tvs ::-         [(TyVar, ArgFlag)] -- The type variable arguments in the associated+         [(TyVar, ForAllTyFlag)] -- The type variable arguments in the associated                             -- default declaration, along with their respective                             -- visibilities (the latter are only used for error                             -- message purposes)@@ -2059,8 +2056,8 @@       let dups = findDupsEq ((==) `on` fst) cpt_tvs_vis in       traverse_         (\d -> let (pat_tv, pat_vis) = NE.head d in failWithTc $-               mkTcRnUnknownMessage $ mkPlainError noHints $-               pprWithExplicitKindsWhen (isInvisibleArgFlag pat_vis) $+              mkTcRnUnknownMessage $ mkPlainError noHints $+               pprWithExplicitKindsWhen (isInvisibleForAllTyFlag pat_vis) $                hang (text "Illegal duplicate variable"                        <+> quotes (ppr pat_tv) <+> text "in:")                   2 (vcat [ppr_eqn, suggestion]))@@ -2242,16 +2239,16 @@   where     (ax_tvs, ax_arg_tys, _) = etaExpandCoAxBranch branch -    arg_triples :: [(Type,Type, ArgFlag)]+    arg_triples :: [(Type,Type, ForAllTyFlag)]     arg_triples = [ (cls_arg_ty, at_arg_ty, vis)                   | (fam_tc_tv, vis, at_arg_ty)                        <- zip3 (tyConTyVars fam_tc)-                               (tyConArgFlags fam_tc ax_arg_tys)+                               (tyConForAllTyFlags fam_tc ax_arg_tys)                                ax_arg_tys                   , Just cls_arg_ty <- [lookupVarEnv mini_env fam_tc_tv] ]      pp_wrong_at_arg vis-      = pprWithExplicitKindsWhen (isInvisibleArgFlag vis) $+      = pprWithExplicitKindsWhen (isInvisibleForAllTyFlag vis) $         vcat [ text "Type indexes must match class instance head"              , text "Expected:" <+> pp_expected_ty              , text "  Actual:" <+> pp_actual_ty ]@@ -2274,11 +2271,11 @@                    tidyTypes tidy_env2 ax_arg_tys      mk_wildcard at_tv = mkTyVarTy (mkTyVar tv_name (tyVarKind at_tv))-    tv_name = mkInternalName (mkAlphaTyVarUnique 1) (mkTyVarOcc "_") noSrcSpan+    tv_name = mkInternalName (mkAlphaTyVarUnique 1) (mkTyVarOccFS (fsLit "_")) noSrcSpan      -- For check_match, bind_me, see     -- Note [Matching in the consistent-instantiation check]-    check_match :: [(Type,Type,ArgFlag)] -> TcM ()+    check_match :: [(Type,Type,ForAllTyFlag)] -> TcM ()     check_match triples = go emptySubst emptySubst triples      go _ _ [] = return ()@@ -2740,9 +2737,9 @@         fkvs = tyCoVarsOfType (tyVarKind tv)      inferred_tvs  = [ binderVar tcb-                    | tcb <- tcbs, Inferred == tyConBinderArgFlag tcb ]+                    | tcb <- tcbs, Inferred == tyConBinderForAllTyFlag tcb ]     specified_tvs = [ binderVar tcb-                    | tcb <- tcbs, Specified == tyConBinderArgFlag tcb ]+                    | tcb <- tcbs, Specified == tyConBinderForAllTyFlag tcb ]      pp_inf  = parens (text "namely:" <+> pprTyVars inferred_tvs)     pp_spec = parens (text "namely:" <+> pprTyVars specified_tvs)@@ -2780,7 +2777,7 @@ -- Free variables of a type, retaining repetitions, and expanding synonyms -- This ignores coercions, as coercions aren't user-written fvType :: Type -> [TyCoVar]-fvType ty | Just exp_ty <- tcView ty = fvType exp_ty+fvType ty | Just exp_ty <- coreView ty = fvType exp_ty fvType (TyVarTy tv)          = [tv] fvType (TyConApp _ tys)      = fvTypes tys fvType (LitTy {})            = []@@ -2797,7 +2794,7 @@  sizeType :: Type -> Int -- Size of a type: the number of variables and constructors-sizeType ty | Just exp_ty <- tcView ty = sizeType exp_ty+sizeType ty | Just exp_ty <- coreView ty = sizeType exp_ty sizeType (TyVarTy {})      = 1 sizeType (TyConApp tc tys) = 1 + sizeTyConAppArgs tc tys sizeType (LitTy {})        = 1
compiler/GHC/ThToHs.hs view
@@ -9,7 +9,6 @@ {-# LANGUAGE ViewPatterns #-}  {-# OPTIONS_GHC -Wno-incomplete-record-updates #-}-{-# OPTIONS_GHC -Wno-incomplete-uni-patterns   #-}  {- (c) The University of Glasgow 2006@@ -28,7 +27,7 @@    ) where -import GHC.Prelude+import GHC.Prelude hiding (head, init, last, tail)  import GHC.Hs as Hs import GHC.Builtin.Names@@ -42,6 +41,7 @@ import GHC.Core.Type as Hs import qualified GHC.Core.Coercion as Coercion ( Role(..) ) import GHC.Builtin.Types+import GHC.Builtin.Types.Prim( fUNTyCon ) import GHC.Types.Basic as Hs import GHC.Types.Fixity as Hs import GHC.Types.ForeignCall@@ -61,6 +61,7 @@ import Data.Bifunctor (first) import Data.Foldable (for_) import Data.List.NonEmpty( NonEmpty (..), nonEmpty )+import qualified Data.List.NonEmpty as NE import Data.Maybe( catMaybes, isNothing ) import Language.Haskell.TH as TH hiding (sigP) import Language.Haskell.TH.Syntax as TH@@ -1223,11 +1224,12 @@ -------------------------------------  cvtHsDo :: HsDoFlavour -> [TH.Stmt] -> CvtM (HsExpr GhcPs)-cvtHsDo do_or_lc stmts-  | null stmts = failWith EmptyStmtListInDoBlock-  | otherwise-  = do  { stmts' <- cvtStmts stmts-        ; let Just (stmts'', last') = snocView stmts'+cvtHsDo do_or_lc stmts = case nonEmpty stmts of+    Nothing -> failWith EmptyStmtListInDoBlock+    Just stmts -> do+        { stmts' <- traverse cvtStmt stmts+        ; let stmts'' = NE.init stmts'+              last' = NE.last stmts'          ; last'' <- case last' of                     (L loc (BodyStmt _ body _ _))@@ -1581,7 +1583,7 @@                      w'' = hsTypeToArrow w'                  returnLA (HsFunTy noAnn w'' x'' y'')              | otherwise-             -> do { fun_tc <- returnLA $ getRdrName funTyCon+             -> do { fun_tc <- returnLA $ getRdrName fUNTyCon                    ; mk_apps (HsTyVar noAnn NotPromoted fun_tc) tys' }            ListT              | Just normals <- m_normals
compiler/GHC/Types/TyThing/Ppr.hs view
@@ -21,7 +21,7 @@ import GHC.Types.TyThing ( TyThing(..), tyThingParent_maybe ) import GHC.Types.Name -import GHC.Core.Type    ( ArgFlag(..), mkTyVarBinders )+import GHC.Core.Type    ( ForAllTyFlag(..), mkTyVarBinders ) import GHC.Core.Coercion.Axiom ( coAxiomTyCon ) import GHC.Core.FamInstEnv( FamInst(..), FamFlavor(..) ) import GHC.Core.TyCo.Ppr ( pprUserForAll, pprTypeApp )@@ -31,7 +31,6 @@ import GHC.Iface.Make ( tyThingToIfaceDecl )  import GHC.Utils.Outputable-import GHC.Utils.Trace  import Data.Maybe ( isJust ) 
compiler/GHC/Utils/Asm.hs view
@@ -12,9 +12,10 @@ import GHC.Utils.Outputable  -- | Generate a section type (e.g. @\@progbits@). See #13937.-sectionType :: Platform -- ^ Target platform+sectionType :: IsLine doc+            => Platform -- ^ Target platform             -> String   -- ^ section type-            -> SDoc     -- ^ pretty assembler fragment+            -> doc      -- ^ pretty assembler fragment sectionType platform ty =     case platformArch platform of       ArchARM{} -> char '%' <> text ty
+ compiler/GHC/Wasm/ControlFlow.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DataKinds, GADTs, RankNTypes, TypeOperators, KindSignatures #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE PatternSynonyms #-}++module GHC.Wasm.ControlFlow+  ( WasmControl(..), (<>), pattern WasmIf, wasmReturn+  , BrTableInterval(..), inclusiveInterval++  , WasmType, WasmTypeTag(..)+  , TypeList(..)+  , WasmFunctionType(..)+  )+where++import GHC.Prelude++import GHC.CmmToAsm.Wasm.Types+import GHC.Utils.Panic++{-|+Module      : GHC.Wasm.ControlFlow+Description : Representation of control-flow portion of the WebAssembly instruction set+-}++inclusiveInterval :: Integer -> Integer -> BrTableInterval+inclusiveInterval lo hi+    | lo <= hi = let count = hi - lo + 1+                 in  BrTableInterval lo count+    | otherwise = panic "GHC.Wasm.ControlFlow: empty interval"++(<>) :: forall s e pre mid post+      . WasmControl s e pre mid+     -> WasmControl s e mid post+     -> WasmControl s e pre post+(<>) = WasmSeq+-- N.B. Fallthrough can't be optimized away because of type checking.++++-- Syntactic sugar.+pattern WasmIf :: WasmFunctionType pre post+               -> e+               -> WasmControl s e pre post+               -> WasmControl s e pre post+               -> WasmControl s e pre post++pattern WasmIf ty e t f =+    WasmPush TagI32 e `WasmSeq` WasmIfTop ty t f++-- More syntactic sugar.+wasmReturn :: WasmTypeTag t -> e -> WasmControl s e (t ': t1star) t2star+wasmReturn tag e = WasmPush tag e `WasmSeq` WasmReturnTop tag
+ compiler/GHC/Wasm/ControlFlow/FromCmm.hs view
@@ -0,0 +1,352 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE DataKinds #-}++module GHC.Wasm.ControlFlow.FromCmm+  ( structuredControl+  )+where++import GHC.Prelude hiding (succ)++import Data.Function+import Data.List (sortBy)+import qualified Data.Tree as Tree++import GHC.Cmm+import GHC.Cmm.Dataflow.Block+import GHC.Cmm.Dataflow.Collections+import GHC.Cmm.Dominators+import GHC.Cmm.Dataflow.Graph+import GHC.Cmm.Dataflow.Label+import GHC.Cmm.Switch++import GHC.CmmToAsm.Wasm.Types++import GHC.Platform++import GHC.Utils.Misc+import GHC.Utils.Panic+import GHC.Utils.Outputable ( Outputable, text, (<+>), ppr+                            , pprWithCommas+                            )++import GHC.Wasm.ControlFlow+++{-|+Module      : GHC.Wasm.ControlFlow.FromCmm+Description : Translation of (reducible) Cmm control flow to WebAssembly++Code in this module can translate any _reducible_ Cmm control-flow+graph to the structured control flow that is required by WebAssembly.+The algorithm is subtle and is described in detail in a draft paper+to be found at https://www.cs.tufts.edu/~nr/pubs/relooper.pdf.+-}++--------------------- Abstraction of Cmm control flow -----------------------++-- | Abstracts the kind of control flow we understand how to convert.+-- A block can be left in one of four ways:+--+--   * Unconditionally+--+--   * Conditionally on a predicate of type `e`+--+--   * To a location determined by the value of a scrutinee of type `e`+--+--   * Not at all.++data ControlFlow e = Unconditional Label+                   | Conditional e Label Label+                   | Switch { _scrutinee :: e+                            , _range :: BrTableInterval+                            , _targets :: [Maybe Label] -- from 0+                            , _defaultTarget :: Maybe Label+                            }+                   | TailCall e++flowLeaving :: Platform -> CmmBlock -> ControlFlow CmmExpr+flowLeaving platform b =+    case lastNode b of+      CmmBranch l -> Unconditional l+      CmmCondBranch c t f _ -> Conditional c t f+      CmmSwitch e targets ->+          let (offset, target_labels) = switchTargetsToTable targets+              (lo, hi) = switchTargetsRange targets+              default_label = switchTargetsDefault targets+              scrutinee = smartPlus platform e offset+              range = inclusiveInterval (lo+toInteger offset) (hi+toInteger offset)+          in  Switch scrutinee range target_labels default_label+      CmmCall { cml_cont = Nothing, cml_target = e } -> TailCall e+      _ -> panic "flowLeaving: unreachable"++----------------------- Evaluation contexts ------------------------------++-- | The syntactic constructs in which Wasm code may be contained.+-- A list of these constructs represents an evaluation context,+-- which is used to determined what level of `br` instruction+-- reaches a given label.++data ContainingSyntax+    = BlockFollowedBy Label+    | LoopHeadedBy Label+    | IfThenElse (Maybe Label) -- ^ Carries the label that follows `if...end`, if any++matchesFrame :: Label -> ContainingSyntax -> Bool+matchesFrame label (BlockFollowedBy l) = label == l+matchesFrame label (LoopHeadedBy l) = label == l+matchesFrame label (IfThenElse (Just l)) = label == l+matchesFrame _ _ = False++data Context = Context { enclosing :: [ContainingSyntax]+                       , fallthrough :: Maybe Label  -- the label can+                                                     -- be reached just by "falling through"+                                                     -- the hole+                       }++instance Outputable Context where+  ppr c | Just l <- fallthrough c =+                    pprWithCommas ppr (enclosing c) <+> text "fallthrough to" <+> ppr l+        | otherwise = pprWithCommas ppr (enclosing c)++emptyContext :: Context+emptyContext = Context [] Nothing++inside :: ContainingSyntax -> Context -> Context+withFallthrough :: Context -> Label -> Context++inside frame c = c { enclosing = frame : enclosing c }+withFallthrough c l = c { fallthrough = Just l }++type CmmActions = Block CmmNode O O++type FT pre post = WasmFunctionType pre post++returns :: FT '[] '[ 'I32]+doesn'tReturn :: FT '[] '[]++returns = WasmFunctionType TypeListNil (TypeListCons TagI32 TypeListNil)+doesn'tReturn = WasmFunctionType TypeListNil TypeListNil++emptyPost :: FT pre post -> Bool+emptyPost (WasmFunctionType _ TypeListNil) = True+emptyPost _ = False++----------------------- Translation ------------------------------++-- | Convert a Cmm CFG to WebAssembly's structured control flow.++structuredControl :: forall expr stmt m .+                     Applicative m+                  => Platform  -- ^ needed for offset calculation+                  -> (Label -> CmmExpr -> m expr) -- ^ translator for expressions+                  -> (Label -> CmmActions -> m stmt) -- ^ translator for straight-line code+                  -> CmmGraph -- ^ CFG to be translated+                  -> m (WasmControl stmt expr '[] '[ 'I32])+structuredControl platform txExpr txBlock g =+   doTree returns dominatorTree emptyContext+ where+   gwd :: GraphWithDominators CmmNode+   gwd = graphWithDominators g++   dominatorTree :: Tree.Tree CmmBlock-- Dominator tree in which children are sorted+                                       -- with highest reverse-postorder number first+   dominatorTree = fmap blockLabeled $ sortTree $ gwdDominatorTree gwd++   doTree     :: FT '[] post -> Tree.Tree CmmBlock -> Context -> m (WasmControl stmt expr '[] post)+   nodeWithin :: forall post .+                 FT '[] post -> CmmBlock -> [Tree.Tree CmmBlock] -> Maybe Label+                                                   -> Context -> m (WasmControl stmt expr '[] post)+   doBranch   :: FT '[] post -> Label -> Label     -> Context -> m (WasmControl stmt expr '[] post)++   doTree fty (Tree.Node x children) context =+       let codeForX = nodeWithin fty x selectedChildren Nothing+       in  if isLoopHeader x then+             WasmLoop fty <$> codeForX loopContext+           else+             codeForX context+     where selectedChildren = case lastNode x of+                                CmmSwitch {} -> children+                                   -- N.B. Unlike `if`, translation of Switch uses only labels.+                                _ -> filter hasMergeRoot children+           loopContext = LoopHeadedBy (entryLabel x) `inside` context+           hasMergeRoot = isMergeNode . Tree.rootLabel++   nodeWithin fty x (y_n:ys) (Just zlabel) context =+       WasmBlock fty <$> nodeWithin fty x (y_n:ys) Nothing context'+     where context' = BlockFollowedBy zlabel `inside` context+   nodeWithin fty x (y_n:ys) Nothing context =+       nodeWithin doesn'tReturn x ys (Just ylabel) (context `withFallthrough` ylabel) <<>>+       doTree fty y_n context+     where ylabel = treeEntryLabel y_n+   nodeWithin fty x [] (Just zlabel) context+     | not (generatesIf x) =+         WasmBlock fty <$> nodeWithin fty x [] Nothing context'+     where context' = BlockFollowedBy zlabel `inside` context+   nodeWithin fty x [] maybeMarks context =+       translationOfX context+     where xlabel = entryLabel x++           translationOfX :: Context -> m (WasmControl stmt expr '[] post)+           translationOfX context =+             (WasmActions <$> txBlock xlabel (nodeBody x)) <<>>+             case flowLeaving platform x of+               Unconditional l -> doBranch fty xlabel l context+               Conditional e t f ->+                 WasmIf fty+                        <$> txExpr xlabel e+                        <*> doBranch fty xlabel t (IfThenElse maybeMarks `inside` context)+                        <*> doBranch fty xlabel f (IfThenElse maybeMarks `inside` context)+               TailCall e -> (WasmPush TagI32 <$> txExpr xlabel e) <<>> pure (WasmReturnTop TagI32)+               Switch e range targets default' ->+                   WasmBrTable <$>  txExpr xlabel e+                               <$~> range+                               <$~> map switchIndex targets+                               <$~> switchIndex default'+            where switchIndex :: Maybe Label -> Int+                  switchIndex Nothing = 0 -- arbitrary; GHC won't go here+                  switchIndex (Just lbl) = index lbl (enclosing context)++   doBranch fty from to context+      | to `elem` fallthrough context && emptyPost fty = pure WasmFallthrough+                -- optimization: `br` is not needed, but it typechecks+                -- only if nothing is expected to be left on the stack++      | isBackward from to = pure $ WasmBr i -- continue+      | isMergeLabel to = pure $ WasmBr i -- exit+      | otherwise = doTree fty (subtreeAt to) context -- inline the code here+     where i = index to (enclosing context)++   generatesIf :: CmmBlock -> Bool+   generatesIf x = case flowLeaving platform x of Conditional {} -> True+                                                  _ -> False++   ---- everything else is utility functions++   treeEntryLabel :: Tree.Tree CmmBlock -> Label+   treeEntryLabel = entryLabel . Tree.rootLabel++   sortTree :: Tree.Tree Label -> Tree.Tree Label+    -- Sort highest rpnum first+   sortTree (Tree.Node label children) =+      Tree.Node label $ sortBy (flip compare `on` (rpnum . Tree.rootLabel)) $+                        map sortTree children++   subtreeAt :: Label -> Tree.Tree CmmBlock+   blockLabeled :: Label -> CmmBlock+   rpnum :: Label -> RPNum-- reverse postorder number of the labeled block+   isMergeLabel :: Label -> Bool+   isMergeNode :: CmmBlock -> Bool+   isLoopHeader :: CmmBlock -> Bool-- identify loop headers+    -- all nodes whose immediate dominator is the given block.+     -- They are produced with the largest RP number first,+     -- so the largest RP number is pushed on the context first.+   dominates :: Label -> Label -> Bool+    -- Domination relation (not just immediate domination)++   blockmap :: LabelMap CmmBlock+   GMany NothingO blockmap NothingO = g_graph g++   blockLabeled l = findLabelIn l blockmap++   rpblocks :: [CmmBlock]+   rpblocks = revPostorderFrom blockmap (g_entry g)++   foldEdges :: forall a . (Label -> Label -> a -> a) -> a -> a+   foldEdges f a =+     foldl (\a (from, to) -> f from to a)+           a+           [(entryLabel from, to) | from <- rpblocks, to <- successors from]++   isMergeLabel l = setMember l mergeBlockLabels+   isMergeNode = isMergeLabel . entryLabel++   isBackward :: Label -> Label -> Bool+   isBackward from to = rpnum to <= rpnum from -- self-edge counts as a backward edge++   subtreeAt label = findLabelIn label subtrees+   subtrees :: LabelMap (Tree.Tree CmmBlock)+   subtrees = addSubtree mapEmpty dominatorTree+     where addSubtree map t@(Tree.Node root children) =+               foldl addSubtree (mapInsert (entryLabel root) t map) children++   mergeBlockLabels :: LabelSet+   -- N.B. A block is a merge node if it is where control flow merges.+   -- That means it is entered by multiple control-flow edges, _except_+   -- back edges don't count.  There must be multiple paths that enter the+   -- block _without_ passing through the block itself.+   mergeBlockLabels =+       setFromList [entryLabel n | n <- rpblocks, big (forwardPreds (entryLabel n))]+    where big [] = False+          big [_] = False+          big (_ : _ : _) = True++          forwardPreds :: Label -> [Label] -- reachable predecessors of reachable blocks,+                                           -- via forward edges only+          forwardPreds = \l -> mapFindWithDefault [] l predmap+              where predmap :: LabelMap [Label]+                    predmap = foldEdges addForwardEdge mapEmpty+                    addForwardEdge from to pm+                        | isBackward from to = pm+                        | otherwise = addToList (from :) to pm++   isLoopHeader = isHeaderLabel . entryLabel+   isHeaderLabel = (`setMember` headers)  -- loop headers+      where headers :: LabelSet+            headers = foldMap headersPointedTo blockmap+            headersPointedTo block =+                setFromList [label | label <- successors block,+                                              dominates label (entryLabel block)]++   index :: Label -> [ContainingSyntax] -> Int+   index _ [] = panic "destination label not in evaluation context"+   index label (frame : context)+       | label `matchesFrame` frame = 0+       | otherwise = 1 + index label context++   rpnum = gwdRPNumber gwd+   dominates lbl blockname =+       lbl == blockname || dominatorsMember lbl (gwdDominatorsOf gwd blockname)++++nodeBody :: CmmBlock -> CmmActions+nodeBody (BlockCC _first middle _last) = middle+++smartPlus :: Platform -> CmmExpr -> Int -> CmmExpr+smartPlus _ e 0 = e+smartPlus platform e k =+    CmmMachOp (MO_Add width) [e, CmmLit (CmmInt (toInteger k) width)]+  where width = cmmExprWidth platform e++addToList :: (IsMap map) => ([a] -> [a]) -> KeyOf map -> map [a] -> map [a]+addToList consx = mapAlter add+    where add Nothing = Just (consx [])+          add (Just xs) = Just (consx xs)++------------------------------------------------------------------+--- everything below here is for diagnostics in case of panic++instance Outputable ContainingSyntax where+    ppr (BlockFollowedBy l) = text "node" <+> ppr l+    ppr (LoopHeadedBy l) = text "loop" <+> ppr l+    ppr (IfThenElse l) = text "if-then-else" <+> ppr l++findLabelIn :: HasDebugCallStack => Label -> LabelMap a -> a+findLabelIn lbl = mapFindWithDefault failed lbl+  where failed =+            pprPanic "label not found in control-flow graph" (ppr lbl)+++infixl 4 <$~>+(<$~>) :: Functor m => m (a -> b) -> a -> m b+(<$~>) f x = fmap ($ x) f++(<<>>) :: forall m s e pre mid post+       . Applicative m+       => m (WasmControl s e pre mid)+       -> m (WasmControl s e mid post)+       -> m (WasmControl s e pre post)+(<<>>) = liftA2 (<>)
compiler/MachRegs.h view
@@ -591,6 +591,41 @@ #define MAX_REAL_FLOAT_REG   6 #define MAX_REAL_DOUBLE_REG  6 +#elif defined(MACHREGS_wasm32)++#define REG_R1             1+#define REG_R2             2+#define REG_R3             3+#define REG_R4             4+#define REG_R5             5+#define REG_R6             6+#define REG_R7             7+#define REG_R8             8+#define REG_R9             9+#define REG_R10            10++#define REG_F1             11+#define REG_F2             12+#define REG_F3             13+#define REG_F4             14+#define REG_F5             15+#define REG_F6             16++#define REG_D1             17+#define REG_D2             18+#define REG_D3             19+#define REG_D4             20+#define REG_D5             21+#define REG_D6             22++#define REG_L1             23++#define REG_Sp             24+#define REG_SpLim          25+#define REG_Hp             26+#define REG_HpLim          27+#define REG_CCCS           28+ #else  #error Cannot find platform to give register info for
compiler/ghc-llvm-version.h view
@@ -3,7 +3,7 @@ #define __GHC_LLVM_VERSION_H__  /* The maximum supported LLVM version number */-#define sUPPORTED_LLVM_VERSION_MAX (14)+#define sUPPORTED_LLVM_VERSION_MAX (15)  /* The minimum supported LLVM version number */ #define sUPPORTED_LLVM_VERSION_MIN (10)
ghc-lib.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.0 build-type: Simple name: ghc-lib-version: 0.20221101+version: 0.20221201 license: BSD3 license-file: LICENSE category: Development@@ -83,7 +83,7 @@         stm,         rts,         hpc == 0.6.*,-        ghc-lib-parser == 0.20221101+        ghc-lib-parser == 0.20221201     build-tool-depends: alex:alex >= 3.1, happy:happy >= 1.19.4     other-extensions:         BangPatterns@@ -198,6 +198,7 @@         GHC.Core.Stats,         GHC.Core.Subst,         GHC.Core.Tidy,+        GHC.Core.TyCo.Compare,         GHC.Core.TyCo.FVs,         GHC.Core.TyCo.Ppr,         GHC.Core.TyCo.Rep,@@ -224,6 +225,7 @@         GHC.Data.Graph.Directed,         GHC.Data.Graph.UnVar,         GHC.Data.IOEnv,+        GHC.Data.List.Infinite,         GHC.Data.List.SetOps,         GHC.Data.Maybe,         GHC.Data.OrdList,@@ -332,10 +334,12 @@         GHC.Platform.Reg.Class,         GHC.Platform.Regs,         GHC.Platform.S390X,+        GHC.Platform.Wasm32,         GHC.Platform.Ways,         GHC.Platform.X86,         GHC.Platform.X86_64,         GHC.Prelude,+        GHC.Prelude.Basic,         GHC.Runtime.Context,         GHC.Runtime.Eval.Types,         GHC.Runtime.Heap.Layout,@@ -502,6 +506,7 @@         Paths_ghc_lib         GHC         GHC.Builtin.Names.TH+        GHC.Builtin.PrimOps.Casts         GHC.Builtin.Types.Literals         GHC.Builtin.Utils         GHC.ByteCode.Asm@@ -530,6 +535,7 @@         GHC.Cmm.Parser.Monad         GHC.Cmm.Pipeline         GHC.Cmm.ProcPoint+        GHC.Cmm.Reducibility         GHC.Cmm.Sink         GHC.Cmm.Switch.Implement         GHC.Cmm.Utils@@ -586,6 +592,11 @@         GHC.CmmToAsm.Reg.Utils         GHC.CmmToAsm.Types         GHC.CmmToAsm.Utils+        GHC.CmmToAsm.Wasm+        GHC.CmmToAsm.Wasm.Asm+        GHC.CmmToAsm.Wasm.FromCmm+        GHC.CmmToAsm.Wasm.Types+        GHC.CmmToAsm.Wasm.Utils         GHC.CmmToAsm.X86         GHC.CmmToAsm.X86.CodeGen         GHC.CmmToAsm.X86.Cond@@ -622,7 +633,10 @@         GHC.CoreToStg.Prep         GHC.Data.Bitmap         GHC.Data.Graph.Base+        GHC.Data.Graph.Collapse         GHC.Data.Graph.Color+        GHC.Data.Graph.Inductive.Graph+        GHC.Data.Graph.Inductive.PatriciaTree         GHC.Data.Graph.Ops         GHC.Data.Graph.Ppr         GHC.Data.UnionFind@@ -649,6 +663,7 @@         GHC.Driver.Config.Stg.Pipeline         GHC.Driver.Config.Stg.Ppr         GHC.Driver.Config.StgToCmm+        GHC.Driver.Config.StgToJS         GHC.Driver.Config.Tidy         GHC.Driver.GenerateCgIPEStub         GHC.Driver.Main@@ -670,6 +685,7 @@         GHC.HsToCore.Foreign.C         GHC.HsToCore.Foreign.Call         GHC.HsToCore.Foreign.Decl+        GHC.HsToCore.Foreign.JavaScript         GHC.HsToCore.Foreign.Prim         GHC.HsToCore.Foreign.Utils         GHC.HsToCore.GuardedRHSs@@ -704,6 +720,10 @@         GHC.Iface.Tidy         GHC.Iface.Tidy.StaticPtrTable         GHC.IfaceToCore+        GHC.JS.Make+        GHC.JS.Ppr+        GHC.JS.Syntax+        GHC.JS.Transform         GHC.Linker         GHC.Linker.Dynamic         GHC.Linker.ExtraObj@@ -777,6 +797,38 @@         GHC.StgToCmm.TagCheck         GHC.StgToCmm.Ticky         GHC.StgToCmm.Utils+        GHC.StgToJS+        GHC.StgToJS.Apply+        GHC.StgToJS.Arg+        GHC.StgToJS.Closure+        GHC.StgToJS.CodeGen+        GHC.StgToJS.CoreUtils+        GHC.StgToJS.DataCon+        GHC.StgToJS.Deps+        GHC.StgToJS.Expr+        GHC.StgToJS.ExprCtx+        GHC.StgToJS.FFI+        GHC.StgToJS.Heap+        GHC.StgToJS.Ids+        GHC.StgToJS.Linker.Linker+        GHC.StgToJS.Linker.Types+        GHC.StgToJS.Linker.Utils+        GHC.StgToJS.Literal+        GHC.StgToJS.Monad+        GHC.StgToJS.Object+        GHC.StgToJS.Prim+        GHC.StgToJS.Printer+        GHC.StgToJS.Profiling+        GHC.StgToJS.Regs+        GHC.StgToJS.Rts.Rts+        GHC.StgToJS.Rts.Types+        GHC.StgToJS.Sinker+        GHC.StgToJS.Stack+        GHC.StgToJS.StaticPtr+        GHC.StgToJS.StgUtils+        GHC.StgToJS.Symbols+        GHC.StgToJS.Types+        GHC.StgToJS.Utils         GHC.SysTools         GHC.SysTools.Ar         GHC.SysTools.Cpp@@ -840,6 +892,8 @@         GHC.Types.Unique.MemoFun         GHC.Unit.Finder         GHC.Utils.Asm+        GHC.Wasm.ControlFlow+        GHC.Wasm.ControlFlow.FromCmm         GHCi.CreateBCO         GHCi.InfoTable         GHCi.ObjLink
ghc-lib/stage0/lib/settings view
@@ -44,7 +44,7 @@ ,("Use inplace MinGW toolchain", "NO") ,("Use interpreter", "YES") ,("Support SMP", "YES")-,("RTS ways", "v thr")+,("RTS ways", "v") ,("Tables next to code", "YES") ,("Leading underscore", "YES") ,("Use LibFFI", "NO")
ghc-lib/stage0/rts/build/include/ghcautoconf.h view
@@ -132,6 +132,10 @@    don't. */ /* #undef HAVE_DECL_MAP_NORESERVE */ +/* Define to 1 if you have the declaration of `program_invocation_short_name',+   and to 0 if you don't. */+#define HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME 0+ /* Define to 1 if you have the <dirent.h> header file. */ #define HAVE_DIRENT_H 1 @@ -165,12 +169,18 @@ /* Define to 1 if you have the `GetModuleFileName' function. */ /* #undef HAVE_GETMODULEFILENAME */ +/* Define to 1 if you have the `getpid' function. */+#define HAVE_GETPID 1+ /* Define to 1 if you have the `getrusage' function. */ #define HAVE_GETRUSAGE 1  /* Define to 1 if you have the `gettimeofday' function. */ #define HAVE_GETTIMEOFDAY 1 +/* Define to 1 if you have the `getuid' function. */+#define HAVE_GETUID 1+ /* Define to 1 if you have the <grp.h> header file. */ #define HAVE_GRP_H 1 @@ -249,6 +259,9 @@ /* Define to 1 if you have the <pwd.h> header file. */ #define HAVE_PWD_H 1 +/* Define to 1 if you have the `raise' function. */+#define HAVE_RAISE 1+ /* Define to 1 if you have the `sched_getaffinity' function. */ /* #undef HAVE_SCHED_GETAFFINITY */ @@ -622,7 +635,7 @@ /* #undef pid_t */  /* The maximum supported LLVM version number */-#define sUPPORTED_LLVM_VERSION_MAX (14)+#define sUPPORTED_LLVM_VERSION_MAX (15)  /* The minimum supported LLVM version number */ #define sUPPORTED_LLVM_VERSION_MIN (10)
libraries/ghci/GHCi/CreateBCO.hs view
@@ -6,6 +6,7 @@ {-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE CPP #-}  -- --  (c) The University of Glasgow 2002-2006@@ -153,7 +154,12 @@ -- without making a thunk turns out to be surprisingly tricky. {-# NOINLINE writeArrayAddr# #-} writeArrayAddr# :: MutableArray# s a -> Int# -> Addr# -> State# s -> State# s+#if defined(js_HOST_ARCH)+-- Addr# isn't coercible with Any with the JS backend.+writeArrayAddr# = error "writeArrayAddr#: currently unsupported with the JS backend"+#else writeArrayAddr# marr i addr s = unsafeCoerce# writeArray# marr i addr s+#endif   #if MIN_VERSION_ghc_prim(0, 7, 0)
libraries/ghci/GHCi/InfoTable.hsc view
@@ -299,8 +299,8 @@   | otherwise = do      code' <- mkJumpToAddr undefined      pure $ case code' of-       Left  xs -> sizeOf (head xs) * length xs-       Right xs -> sizeOf (head xs) * length xs+       Left  (xs :: [Word8])  -> sizeOf (undefined :: Word8)  * length xs+       Right (xs :: [Word32]) -> sizeOf (undefined :: Word32) * length xs  -- Note: Must return proper pointer for use in a closure #if MIN_VERSION_rts(1,0,1)