ghc-lib 0.20211001 → 0.20211101
raw patch · 93 files changed
+4068/−2460 lines, 93 filesdep ~bytestringdep ~ghc-lib-parserdep ~ghc-prim
Dependency ranges changed: bytestring, ghc-lib-parser, ghc-prim, time
Files
- compiler/GHC.hs +38/−16
- compiler/GHC/CmmToAsm.hs +2/−2
- compiler/GHC/CmmToAsm/AArch64/CodeGen.hs +5/−0
- compiler/GHC/CmmToAsm/Dwarf/Types.hs +1/−1
- compiler/GHC/CmmToAsm/Reg/Linear.hs +6/−15
- compiler/GHC/CmmToAsm/Reg/Linear/Base.hs +42/−2
- compiler/GHC/CmmToAsm/Reg/Linear/JoinToTargets.hs +2/−2
- compiler/GHC/Core/Opt/CprAnal.hs +26/−86
- compiler/GHC/Core/Opt/DmdAnal.hs +170/−99
- compiler/GHC/Core/Opt/Pipeline.hs +2/−1
- compiler/GHC/Core/Opt/SetLevels.hs +43/−34
- compiler/GHC/Core/Opt/Simplify.hs +15/−44
- compiler/GHC/Core/Opt/SpecConstr.hs +1/−1
- compiler/GHC/Core/Opt/WorkWrap.hs +38/−33
- compiler/GHC/Core/Opt/WorkWrap/Utils.hs +230/−163
- compiler/GHC/Driver/Backpack.hs +34/−29
- compiler/GHC/Driver/Config/CmmToAsm.hs +5/−0
- compiler/GHC/Driver/Config/Finder.hs +29/−0
- compiler/GHC/Driver/Main.hs +53/−19
- compiler/GHC/Driver/Make.hs +164/−119
- compiler/GHC/Driver/MakeFile.hs +2/−2
- compiler/GHC/Driver/Pipeline.hs +14/−74
- compiler/GHC/Driver/Pipeline/Execute.hs +92/−17
- compiler/GHC/Hs/Syn/Type.hs +1/−1
- compiler/GHC/HsToCore.hs +4/−1
- compiler/GHC/HsToCore/Arrows.hs +11/−53
- compiler/GHC/HsToCore/Binds.hs +3/−6
- compiler/GHC/HsToCore/Expr.hs +31/−235
- compiler/GHC/HsToCore/Expr.hs-boot +1/−1
- compiler/GHC/HsToCore/ListComp.hs +4/−7
- compiler/GHC/HsToCore/Match.hs +2/−2
- compiler/GHC/HsToCore/Match/Constructor.hs +5/−4
- compiler/GHC/HsToCore/Monad.hs +6/−115
- compiler/GHC/HsToCore/Pmc/Utils.hs +8/−1
- compiler/GHC/HsToCore/Utils.hs +6/−69
- compiler/GHC/Iface/Ext/Ast.hs +28/−55
- compiler/GHC/Iface/Ext/Types.hs +1/−0
- compiler/GHC/Iface/Load.hs +59/−42
- compiler/GHC/Iface/Recomp.hs +39/−11
- compiler/GHC/IfaceToCore.hs +21/−13
- compiler/GHC/Linker/Dynamic.hs +1/−1
- compiler/GHC/Linker/Loader.hs +28/−14
- compiler/GHC/Linker/Static.hs +2/−2
- compiler/GHC/Plugins.hs +4/−0
- compiler/GHC/Rename/Bind.hs +8/−5
- compiler/GHC/Rename/Env.hs +5/−3
- compiler/GHC/Rename/Expr.hs +7/−4
- compiler/GHC/Rename/Names.hs +64/−22
- compiler/GHC/Rename/Unbound.hs +4/−3
- compiler/GHC/Rename/Utils.hs +2/−1
- compiler/GHC/Runtime/Eval.hs +16/−15
- compiler/GHC/Settings/IO.hs +0/−6
- compiler/GHC/StgToCmm/Foreign.hs-boot +6/−0
- compiler/GHC/StgToCmm/Ticky.hs +40/−23
- compiler/GHC/StgToCmm/Utils.hs +1/−2
- compiler/GHC/Tc/Deriv.hs +85/−194
- compiler/GHC/Tc/Deriv/Functor.hs +8/−3
- compiler/GHC/Tc/Deriv/Generics.hs +26/−33
- compiler/GHC/Tc/Deriv/Utils.hs +62/−87
- compiler/GHC/Tc/Errors.hs +116/−37
- compiler/GHC/Tc/Errors/Hole.hs +60/−35
- compiler/GHC/Tc/Gen/App.hs +240/−6
- compiler/GHC/Tc/Gen/Arrow.hs +33/−11
- compiler/GHC/Tc/Gen/Bind.hs +9/−2
- compiler/GHC/Tc/Gen/Expr.hs +40/−116
- compiler/GHC/Tc/Gen/Head.hs +32/−0
- compiler/GHC/Tc/Gen/HsType.hs +8/−7
- compiler/GHC/Tc/Gen/Match.hs +33/−11
- compiler/GHC/Tc/Gen/Pat.hs +53/−37
- compiler/GHC/Tc/Gen/Rule.hs +13/−8
- compiler/GHC/Tc/Gen/Sig.hs +11/−6
- compiler/GHC/Tc/Instance/Class.hs +4/−5
- compiler/GHC/Tc/Instance/FunDeps.hs +1/−1
- compiler/GHC/Tc/Module.hs +42/−30
- compiler/GHC/Tc/Plugin.hs +2/−2
- compiler/GHC/Tc/Solver.hs +76/−19
- compiler/GHC/Tc/Solver/Canonical.hs +143/−2
- compiler/GHC/Tc/Solver/Interact.hs +27/−11
- compiler/GHC/Tc/Solver/Monad.hs +62/−42
- compiler/GHC/Tc/TyCl.hs +45/−46
- compiler/GHC/Tc/TyCl/Build.hs +7/−6
- compiler/GHC/Tc/TyCl/Instance.hs +8/−4
- compiler/GHC/Tc/Utils/Backpack.hs +22/−40
- compiler/GHC/Tc/Utils/Concrete.hs +521/−0
- compiler/GHC/Tc/Utils/Instantiate.hs +53/−17
- compiler/GHC/Tc/Utils/Monad.hs +2/−1
- compiler/GHC/Tc/Utils/TcMType.hs +66/−59
- compiler/GHC/Tc/Utils/Unify.hs +19/−50
- compiler/GHC/Tc/Utils/Zonk.hs +5/−20
- compiler/GHC/Tc/Validity.hs +21/−26
- compiler/GHC/Unit/Finder.hs +665/−0
- ghc-lib.cabal +12/−9
- ghc-lib/stage0/lib/ghcautoconf.h +4/−1
compiler/GHC.hs view
@@ -53,7 +53,7 @@ -- * Loading\/compiling the program depanal, depanalE,- load, LoadHowMuch(..), InteractiveImport(..),+ load, loadWithCache, LoadHowMuch(..), InteractiveImport(..), SuccessFlag(..), succeeded, failed, defaultWarnErrLogger, WarnErrLogger, workingDirectoryChanged,@@ -63,6 +63,7 @@ TypecheckedMod, ParsedMod, moduleInfo, renamedSource, typecheckedSource, parsedSource, coreModule,+ PkgQual(..), -- ** Compiling to Core CoreModule(..),@@ -116,6 +117,8 @@ -- ** Inspecting the current context getBindings, getInsts, getPrintUnqual, findModule, lookupModule,+ findQualifiedModule, lookupQualifiedModule,+ renamePkgQualM, renameRawPkgQualM, isModuleTrusted, moduleTrustReqs, getNamesInScope, getRdrNamesInScope,@@ -321,7 +324,6 @@ import qualified GHC.Linker.Loader as Loader import GHC.Runtime.Loader import GHC.Runtime.Eval-import GHC.Runtime.Eval.Types import GHC.Runtime.Interpreter import GHC.Runtime.Context import GHCi.RemoteTypes@@ -338,6 +340,7 @@ import GHC.Data.StringBuffer import GHC.Data.FastString import qualified GHC.LanguageExtensions as LangExt+import GHC.Rename.Names (renamePkgQual, renameRawPkgQual) import GHC.Tc.Utils.Monad ( finalSafeMode, fixSafeInstances, initIfaceTcRn ) import GHC.Tc.Types@@ -387,6 +390,8 @@ import GHC.Types.Name.Env import GHC.Types.Name.Ppr import GHC.Types.TypeEnv+import GHC.Types.BreakInfo+import GHC.Types.PkgQual import GHC.Unit import GHC.Unit.Env@@ -1469,7 +1474,7 @@ -- | get the GlobalRdrEnv for a session getGRE :: GhcMonad m => m GlobalRdrEnv-getGRE = withSession $ \hsc_env-> return $ ic_rn_gbl_env (hsc_IC hsc_env)+getGRE = withSession $ \hsc_env-> return $ icReaderEnv (hsc_IC hsc_env) -- | Retrieve all type and family instances in the environment, indexed -- by 'Name'. Each name's lists will contain every instance in which that name@@ -1631,37 +1636,49 @@ -- filesystem and package database to find the corresponding 'Module', -- using the algorithm that is used for an @import@ declaration. findModule :: GhcMonad m => ModuleName -> Maybe FastString -> m Module-findModule mod_name maybe_pkg = withSession $ \hsc_env -> do+findModule mod_name maybe_pkg = do+ pkg_qual <- renamePkgQualM maybe_pkg+ findQualifiedModule pkg_qual mod_name+++findQualifiedModule :: GhcMonad m => PkgQual -> ModuleName -> m Module+findQualifiedModule pkgqual mod_name = withSession $ \hsc_env -> do let fc = hsc_FC hsc_env let home_unit = hsc_home_unit hsc_env let units = hsc_units hsc_env let dflags = hsc_dflags hsc_env let fopts = initFinderOpts dflags- case maybe_pkg of- Just pkg | not (isHomeUnit home_unit (fsToUnit pkg)) && pkg /= fsLit "this" -> liftIO $ do- res <- findImportedModule fc fopts units home_unit mod_name maybe_pkg- case res of- Found _ m -> return m- err -> throwOneError $ noModError hsc_env noSrcSpan mod_name err- _otherwise -> do+ case pkgqual of+ ThisPkg _ -> do home <- lookupLoadedHomeModule mod_name case home of Just m -> return m Nothing -> liftIO $ do- res <- findImportedModule fc fopts units home_unit mod_name maybe_pkg+ res <- findImportedModule fc fopts units home_unit mod_name pkgqual case res of Found loc m | not (isHomeModule home_unit m) -> return m | otherwise -> modNotLoadedError dflags m loc err -> throwOneError $ noModError hsc_env noSrcSpan mod_name err- where + _ -> liftIO $ do+ res <- findImportedModule fc fopts units home_unit mod_name pkgqual+ case res of+ Found _ m -> return m+ err -> throwOneError $ noModError hsc_env noSrcSpan mod_name err + modNotLoadedError :: DynFlags -> Module -> ModLocation -> IO a modNotLoadedError dflags m loc = throwGhcExceptionIO $ CmdLineError $ showSDoc dflags $ text "module is not loaded:" <+> quotes (ppr (moduleName m)) <+> parens (text (expectJust "modNotLoadedError" (ml_hs_file loc))) +renamePkgQualM :: GhcMonad m => Maybe FastString -> m PkgQual+renamePkgQualM p = withSession $ \hsc_env -> pure (renamePkgQual (hsc_unit_env hsc_env) p)++renameRawPkgQualM :: GhcMonad m => RawPkgQual -> m PkgQual+renameRawPkgQualM p = withSession $ \hsc_env -> pure (renameRawPkgQual (hsc_unit_env hsc_env) p)+ -- | Like 'findModule', but differs slightly when the module refers to -- a source file, and the file has not been loaded via 'load'. In -- this case, 'findModule' will throw an error (module not loaded),@@ -1670,8 +1687,12 @@ -- returned. If not, the usual module-not-found error will be thrown. -- lookupModule :: GhcMonad m => ModuleName -> Maybe FastString -> m Module-lookupModule mod_name (Just pkg) = findModule mod_name (Just pkg)-lookupModule mod_name Nothing = withSession $ \hsc_env -> do+lookupModule mod_name maybe_pkg = do+ pkgqual <- renamePkgQualM maybe_pkg+ lookupQualifiedModule pkgqual mod_name++lookupQualifiedModule :: GhcMonad m => PkgQual -> ModuleName -> m Module+lookupQualifiedModule NoPkgQual mod_name = withSession $ \hsc_env -> do home <- lookupLoadedHomeModule mod_name case home of Just m -> return m@@ -1680,10 +1701,11 @@ let units = hsc_units hsc_env let dflags = hsc_dflags hsc_env let fopts = initFinderOpts dflags- res <- findExposedPackageModule fc fopts units mod_name Nothing+ res <- findExposedPackageModule fc fopts units mod_name NoPkgQual case res of Found _ m -> return m err -> throwOneError $ noModError hsc_env noSrcSpan mod_name err+lookupQualifiedModule pkgqual mod_name = findQualifiedModule pkgqual mod_name lookupLoadedHomeModule :: GhcMonad m => ModuleName -> m (Maybe Module) lookupLoadedHomeModule mod_name = withSession $ \hsc_env ->
compiler/GHC/CmmToAsm.hs view
@@ -496,7 +496,7 @@ -- tag instructions with register liveness information -- also drops dead code. We don't keep the cfg in sync on -- some backends, so don't use it there.- let livenessCfg = if backendMaintainsCfg platform+ let livenessCfg = if ncgEnableDeadCodeElimination config then Just nativeCfgWeights else Nothing let (withLiveness, usLive) =@@ -643,7 +643,7 @@ let getBlks (CmmProc _info _lbl _live (ListGraph blocks)) = blocks getBlks _ = [] - when ( backendMaintainsCfg platform &&+ when ( ncgEnableDeadCodeElimination config && (ncgAsmLinting config || debugIsOn )) $ do let blocks = concatMap getBlks shorted let labels = setFromList $ fmap blockId blocks :: LabelSet
compiler/GHC/CmmToAsm/AArch64/CodeGen.hs view
@@ -445,6 +445,11 @@ -- TODO handle CmmInt 0 specially, use wzr or xzr. + CmmInt i W8 | i >= 0 -> do+ return (Any (intFormat W8) (\dst -> unitOL $ annExpr expr (MOV (OpReg W8 dst) (OpImm (ImmInteger (narrowU W8 i))))))+ CmmInt i W16 | i >= 0 -> do+ return (Any (intFormat W16) (\dst -> unitOL $ annExpr expr (MOV (OpReg W16 dst) (OpImm (ImmInteger (narrowU W16 i))))))+ CmmInt i W8 -> do return (Any (intFormat W8) (\dst -> unitOL $ annExpr expr (MOV (OpReg W8 dst) (OpImm (ImmInteger (narrowS W8 i)))))) CmmInt i W16 -> do
compiler/GHC/CmmToAsm/Dwarf/Types.hs view
@@ -600,7 +600,7 @@ = pprString' $ hcat $ map escapeChar $ if str `lengthIs` utf8EncodedLength str then str- else map (chr . fromIntegral) $ BS.unpack $ bytesFS $ mkFastString str+ else map (chr . fromIntegral) $ BS.unpack $ utf8EncodeString str -- | Escape a single non-unicode character escapeChar :: Char -> SDoc
compiler/GHC/CmmToAsm/Reg/Linear.hs view
@@ -140,7 +140,6 @@ import Data.Maybe import Data.List (partition, nub) import Control.Monad-import Control.Applicative -- ----------------------------------------------------------------------------- -- Top level of the register allocator@@ -253,7 +252,7 @@ linearRegAlloc' config initFreeRegs entry_ids block_live sccs = do us <- getUniqueSupplyM let !(_, !stack, !stats, !blocks) =- runR config mapEmpty initFreeRegs emptyRegMap emptyStackMap us+ runR config emptyBlockAssignment initFreeRegs emptyRegMap emptyStackMap us $ linearRA_SCCs entry_ids block_live [] sccs return (blocks, stats, getStackUse stack) @@ -323,7 +322,7 @@ go (b@(BasicBlock id _) : blocks) next_round accum madeProgress = do block_assig <- getBlockAssigR- if isJust (mapLookup id block_assig) || id `elem` entry_ids+ if isJust (lookupBlockAssignment id block_assig) || id `elem` entry_ids then do b' <- processBlock block_live b go blocks next_round (b' : accum) True @@ -355,7 +354,7 @@ initBlock id block_live = do platform <- getPlatform block_assig <- getBlockAssigR- case mapLookup id block_assig of+ case lookupBlockAssignment id block_assig of -- no prior info about this block: we must consider -- any fixed regs to be allocated, but we can ignore -- virtual regs (presumably this is part of a loop,@@ -852,19 +851,11 @@ -- variables are likely to end up in the same registers at the -- end and start of the loop, avoiding redundant reg-reg moves. -- Note: I tried returning a list of past assignments, but that--- turned out to barely matter but added a few tenths of--- a percent to compile time.+-- turned out to barely matter. findPrefRealReg :: VirtualReg -> RegM freeRegs (Maybe RealReg) findPrefRealReg vreg = do- bassig <- getBlockAssigR :: RegM freeRegs (BlockMap (freeRegs,RegMap Loc))- return $ foldr (findVirtRegAssig) Nothing bassig- where- findVirtRegAssig :: (freeRegs,RegMap Loc) -> Maybe RealReg -> Maybe RealReg- findVirtRegAssig assig z =- z <|> case lookupUFM (toVRegMap $ snd assig) vreg of- Just (InReg real_reg) -> Just real_reg- Just (InBoth real_reg _) -> Just real_reg- _ -> z+ bassig <- getBlockAssigR :: RegM freeRegs (BlockAssignment freeRegs)+ return $ lookupFirstUsed vreg bassig -- reading is redundant with reason, but we keep it around because it's -- convenient and it maintains the recursive structure of the allocator. -- EZY
compiler/GHC/CmmToAsm/Reg/Linear/Base.hs view
@@ -1,8 +1,13 @@+{-# LANGUAGE RecordWildCards #-} -- | Put common type definitions here to break recursive module dependencies. module GHC.CmmToAsm.Reg.Linear.Base ( BlockAssignment,+ lookupBlockAssignment,+ lookupFirstUsed,+ emptyBlockAssignment,+ updateBlockAssignment, Loc(..), regsOfLoc,@@ -29,6 +34,8 @@ import GHC.Types.Unique.FM import GHC.Types.Unique.Supply import GHC.Cmm.BlockId+import GHC.Cmm.Dataflow.Collections+import GHC.CmmToAsm.Reg.Utils data ReadingOrWriting = Reading | Writing deriving (Eq,Ord) @@ -37,8 +44,41 @@ -- target a particular label. We have to insert fixup code to make -- the register assignments from the different sources match up. ---type BlockAssignment freeRegs- = BlockMap (freeRegs, RegMap Loc)+data BlockAssignment freeRegs+ = BlockAssignment { blockMap :: !(BlockMap (freeRegs, RegMap Loc))+ , firstUsed :: !(UniqFM VirtualReg RealReg) }++-- | Find the register mapping for a specific BlockId.+lookupBlockAssignment :: BlockId -> BlockAssignment freeRegs -> Maybe (freeRegs, RegMap Loc)+lookupBlockAssignment bid ba = mapLookup bid (blockMap ba)++-- | Lookup which register a virtual register was first assigned to.+lookupFirstUsed :: VirtualReg -> BlockAssignment freeRegs -> Maybe RealReg+lookupFirstUsed vr ba = lookupUFM (firstUsed ba) vr++-- | An initial empty 'BlockAssignment'+emptyBlockAssignment :: BlockAssignment freeRegs+emptyBlockAssignment = BlockAssignment mapEmpty mempty++-- | Add new register mappings for a specific block.+updateBlockAssignment :: BlockId+ -> (freeRegs, RegMap Loc)+ -> BlockAssignment freeRegs+ -> BlockAssignment freeRegs+updateBlockAssignment dest (freeRegs, regMap) (BlockAssignment {..}) =+ BlockAssignment (mapInsert dest (freeRegs, regMap) blockMap)+ (mergeUFM combWithExisting id (mapMaybeUFM fromLoc) (firstUsed) (toVRegMap regMap))+ where+ -- The blocks are processed in dependency order, so if there's already an+ -- entry in the map then keep that assignment rather than writing the new+ -- assignment.+ combWithExisting :: RealReg -> Loc -> Maybe RealReg+ combWithExisting old_reg _ = Just $ old_reg++ fromLoc :: Loc -> Maybe RealReg+ fromLoc (InReg rr) = Just rr+ fromLoc (InBoth rr _) = Just rr+ fromLoc _ = Nothing -- | Where a vreg is currently stored
compiler/GHC/CmmToAsm/Reg/Linear/JoinToTargets.hs view
@@ -100,7 +100,7 @@ , not (elemUniqSet_Directly reg live_set) , r <- regsOfLoc loc ] - case mapLookup dest block_assig of+ case lookupBlockAssignment dest block_assig of Nothing -> joinToTargets_first block_live new_blocks block_id instr dest dests@@ -136,7 +136,7 @@ let freeregs' = foldl' (flip $ frReleaseReg platform) freeregs to_free -- remember the current assignment on entry to this block.- setBlockAssigR (mapInsert dest (freeregs', src_assig) block_assig)+ setBlockAssigR (updateBlockAssignment dest (freeregs', src_assig) block_assig) joinToTargets' block_live new_blocks block_id instr dests
compiler/GHC/Core/Opt/CprAnal.hs view
@@ -21,18 +21,15 @@ import GHC.Types.Demand import GHC.Types.Cpr -import GHC.Core.DataCon import GHC.Core.FamInstEnv-import GHC.Core.Multiplicity-import GHC.Core.Opt.WorkWrap.Utils-import GHC.Core.TyCon+import GHC.Core.DataCon import GHC.Core.Type-import GHC.Core.Utils ( exprIsHNF, dumpIdInfoOfProgram, normSplitTyConApp_maybe )+import GHC.Core.Utils import GHC.Core import GHC.Core.Seq+import GHC.Core.Opt.WorkWrap.Utils import GHC.Data.Graph.UnVar -- for UnVarSet-import GHC.Data.Maybe ( isJust ) import GHC.Utils.Outputable import GHC.Utils.Misc@@ -193,12 +190,12 @@ cprAnalTopBind env (NonRec id rhs) = (env', NonRec id' rhs') where- (id', rhs', env') = cprAnalBind TopLevel env id rhs+ (id', rhs', env') = cprAnalBind env id rhs cprAnalTopBind env (Rec pairs) = (env', Rec pairs') where- (env', pairs') = cprFix TopLevel env pairs+ (env', pairs') = cprFix env pairs -- -- * Analysing expressions@@ -256,13 +253,13 @@ cprAnal' env (Let (NonRec id rhs) body) = (body_ty, Let (NonRec id' rhs') body') where- (id', rhs', env') = cprAnalBind NotTopLevel env id rhs+ (id', rhs', env') = cprAnalBind env id rhs (body_ty, body') = cprAnal env' body cprAnal' env (Let (Rec pairs) body) = body_ty `seq` (body_ty, Let (Rec pairs') body') where- (env', pairs') = cprFix NotTopLevel env pairs+ (env', pairs') = cprFix env pairs (body_ty, body') = cprAnal env' body cprAnalAlt@@ -395,11 +392,10 @@ -- -- Recursive bindings-cprFix :: TopLevelFlag- -> AnalEnv -- Does not include bindings for this binding+cprFix :: AnalEnv -- Does not include bindings for this binding -> [(Id,CoreExpr)] -> (AnalEnv, [(Id,CoreExpr)]) -- Binders annotated with CPR info-cprFix top_lvl orig_env orig_pairs+cprFix orig_env orig_pairs = loop 1 init_env init_pairs where init_sig id@@ -432,17 +428,16 @@ where go env (id, rhs) = (env', (id', rhs')) where- (id', rhs', env') = cprAnalBind top_lvl env id rhs+ (id', rhs', env') = cprAnalBind env id rhs -- | Process the RHS of the binding for a sensible arity, add the CPR signature -- to the Id, and augment the environment with the signature as well. cprAnalBind- :: TopLevelFlag- -> AnalEnv+ :: AnalEnv -> Id -> CoreExpr -> (Id, CoreExpr, AnalEnv)-cprAnalBind top_lvl env id rhs+cprAnalBind env id rhs | isDFunId id -- Never give DFuns the CPR property; we'll never save allocs. = (id, rhs, extendSigEnv env id topCprSig) -- See Note [CPR for data structures]@@ -455,10 +450,8 @@ -- possibly trim thunk CPR info rhs_ty' -- See Note [CPR for thunks]- | stays_thunk = trimCprTy rhs_ty- -- See Note [CPR for sum types]- | returns_local_sum = trimCprTy rhs_ty- | otherwise = rhs_ty+ | stays_thunk = trimCprTy rhs_ty+ | otherwise = rhs_ty -- See Note [Arity trimming for CPR signatures] sig = mkCprSigForArity (idArity id) rhs_ty' id' = setIdCprSig id sig@@ -468,14 +461,6 @@ stays_thunk = is_thunk && not_strict is_thunk = not (exprIsHNF rhs) && not (isJoinId id) not_strict = not (isStrUsedDmd (idDemandInfo id))- -- See Note [CPR for sum types]- (_, ret_ty) = splitPiTys (idType id)- returns_product- | Just (tc, _, _) <- normSplitTyConApp_maybe (ae_fam_envs env) ret_ty- = isJust (tyConSingleAlgDataCon_maybe tc)- | otherwise- = False- returns_local_sum = not (isTopLevel top_lvl) && not returns_product isDataStructure :: Id -> Bool -- See Note [CPR for data structures]@@ -653,30 +638,23 @@ -- See Note [CPR for binders that will be unboxed]. extendSigEnvForArg :: AnalEnv -> Id -> AnalEnv extendSigEnvForArg env id- = extendSigEnv env id (CprSig (argCprType env (idType id) (idDemandInfo id)))+ = extendSigEnv env id (CprSig (argCprType (idDemandInfo id))) -- | Produces a 'CprType' according to how a strict argument will be unboxed. -- Examples: ----- * A head-strict demand @1L@ on @Int@ would translate to @1@--- * A product demand @1P(1L,L)@ on @(Int, Bool)@ would translate to @1(1,)@--- * A product demand @1P(1L,L)@ on @(a , Bool)@ would translate to @1(,)@,--- because the unboxing strategy would not unbox the @a@.-argCprType :: AnalEnv -> Type -> Demand -> CprType-argCprType env arg_ty dmd = CprType 0 (go arg_ty dmd)+-- * A head-strict demand @1!L@ would translate to @1@+-- * A product demand @1!P(1!L,L)@ would translate to @1(1,)@+-- * A product demand @1!P(1L,L)@ would translate to @1(,)@,+-- because the first field will not be unboxed.+argCprType :: Demand -> CprType+argCprType dmd = CprType 0 (go dmd) where- go ty dmd- | Unbox (DataConPatContext { dcpc_dc = dc, dcpc_tc_args = tc_args }) ds- <- wantToUnboxArg (ae_fam_envs env) MaybeArgOfInlineableFun ty dmd- -- No existentials; see Note [Which types are unboxed?])- -- Otherwise we'd need to call dataConRepInstPat here and thread a- -- UniqSupply. So argCprType is a bit less aggressive than it could- -- be, for the sake of coding convenience.- , null (dataConExTyCoVars dc)- , let arg_tys = map scaledThing (dataConInstArgTys dc tc_args)- = ConCpr (dataConTag dc) (zipWith go arg_tys ds)- | otherwise- = topCpr+ go (n :* sd)+ | isAbs n = topCpr+ | Prod Unboxed ds <- sd = ConCpr fIRST_TAG (strictMap go ds)+ | Poly Unboxed _ <- sd = ConCpr fIRST_TAG []+ | otherwise = topCpr {- Note [Safe abortion in the fixed-point iteration] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@@ -750,44 +728,6 @@ See Historic Note [Optimistic field binder CPR]. * See Note [CPR examples]--Note [CPR for sum types]-~~~~~~~~~~~~~~~~~~~~~~~~-Aug 21: This Note is out of date. It says that the subsequent WW split after-CPR for sum types destroys join points, but that is no longer correct; we have-the tools to track join points today and simply don't WW join points,-see Note [Don't w/w join points for CPR].-Yet the issue persists. It is tracked in #5075 and the ultimate reason is a bit-unclear. All regressions involve CPR'ing functions returning lists, which are-recursive data structures. If we don't CPR them-(due to Note [CPR for recursive data constructors]), we might be able to finally-remove this hack, after doing the proper perf checks.--Historic Note:--At the moment we do not do CPR for let-bindings that- * non-top level- * bind a sum type-Reason: I found that in some benchmarks we were losing let-no-escapes,-which messed it all up. Example- let j = \x. ....- in case y of- True -> j False- False -> j True-If we w/w this we get- let j' = \x. ....- in case y of- True -> case j' False of { (# a #) -> Just a }- False -> case j' True of { (# a #) -> Just a }-Notice that j' is not a let-no-escape any more.--However this means in turn that the *enclosing* function-may be CPR'd (via the returned Justs). But in the case of-sums, there may be Nothing alternatives; and that messes-up the sum-type CPR.--Conclusion: only do this for products. It's still not-guaranteed OK for products, but sums definitely lose sometimes. Note [CPR for thunks] ~~~~~~~~~~~~~~~~~~~~~
compiler/GHC/Core/Opt/DmdAnal.hs view
@@ -32,7 +32,8 @@ import GHC.Core.TyCon import GHC.Core.Type import GHC.Core.FVs ( rulesRhsFreeIds, bndrRuleAndUnfoldingIds )-import GHC.Core.Coercion ( Coercion, coVarsOfCo )+import GHC.Core.Coercion ( Coercion )+import GHC.Core.TyCo.FVs ( coVarsOfCos ) import GHC.Core.FamInstEnv import GHC.Core.Opt.Arity ( typeArity ) import GHC.Utils.Misc@@ -55,8 +56,9 @@ -} -- | Options for the demand analysis-newtype DmdAnalOpts = DmdAnalOpts- { dmd_strict_dicts :: Bool -- ^ Use strict dictionaries+data DmdAnalOpts = DmdAnalOpts+ { dmd_strict_dicts :: !Bool -- ^ Use strict dictionaries+ , dmd_unbox_width :: !Int -- ^ Use strict dictionaries } -- This is a strict alternative to (,)@@ -276,8 +278,10 @@ where WithDmdType body_ty body' = anal_body env WithDmdType body_ty' id_dmd = findBndrDmd env body_ty id- !id' = setBindIdDemandInfo top_lvl id id_dmd- (rhs_ty, rhs') = dmdAnalStar env (dmdTransformThunkDmd rhs id_dmd) rhs+ -- See Note [Finalising boxity for demand signature] in "GHC.Core.Opt.WorkWrap.Utils"+ id_dmd' = finaliseBoxity (ae_fam_envs env) NotInsideInlineableFun (idType id) id_dmd+ !id' = setBindIdDemandInfo top_lvl id id_dmd'+ (rhs_ty, rhs') = dmdAnalStar env (dmdTransformThunkDmd rhs id_dmd') rhs -- See Note [Absence analysis for stable unfoldings and RULES] rule_fvs = bndrRuleAndUnfoldingIds id@@ -425,21 +429,24 @@ | is_single_data_alt alt = let WithDmdType rhs_ty rhs' = dmdAnal env dmd rhs- WithDmdType alt_ty1 dmds = findBndrsDmds env rhs_ty bndrs+ WithDmdType alt_ty1 fld_dmds = findBndrsDmds env rhs_ty bndrs WithDmdType alt_ty2 case_bndr_dmd = findBndrDmd env alt_ty1 case_bndr+ !case_bndr' = setIdDemandInfo case_bndr case_bndr_dmd -- Evaluation cardinality on the case binder is irrelevant and a no-op. -- What matters is its nested sub-demand!+ -- NB: If case_bndr_dmd is absDmd, boxity will say Unboxed, which is+ -- what we want, because then `seq` will put a `seqDmd` on its scrut. (_ :* case_bndr_sd) = case_bndr_dmd -- Compute demand on the scrutinee -- FORCE the result, otherwise thunks will end up retaining the -- whole DmdEnv !(!bndrs', !scrut_sd) | DataAlt _ <- alt- , id_dmds <- addCaseBndrDmd case_bndr_sd dmds- -- See Note [Demand on scrutinee of a product case]- = let !new_info = setBndrsDemandInfo bndrs id_dmds- !new_prod = mkProd id_dmds- in (new_info, new_prod)+ -- See Note [Demand on the scrutinee of a product case]+ -- See Note [Demand on case-alternative binders]+ , (!scrut_sd, fld_dmds') <- addCaseBndrDmd case_bndr_sd fld_dmds+ , let !bndrs' = setBndrsDemandInfo bndrs fld_dmds'+ = (bndrs', scrut_sd) | otherwise -- __DEFAULT and literal alts. Simply add demands and discard the -- evaluation cardinality, as we evaluate the scrutinee exactly once.@@ -454,7 +461,6 @@ WithDmdType scrut_ty scrut' = dmdAnal env scrut_sd scrut res_ty = alt_ty3 `plusDmdType` toPlusDmdArg scrut_ty- !case_bndr' = setIdDemandInfo case_bndr case_bndr_dmd in -- pprTrace "dmdAnal:Case1" (vcat [ text "scrut" <+> ppr scrut -- , text "dmd" <+> ppr dmd@@ -482,8 +488,9 @@ WithDmdType rest_ty as' = combineAltDmds as in WithDmdType (lubDmdType cur_ty rest_ty) (a':as') - WithDmdType scrut_ty scrut' = dmdAnal env topSubDmd scrut- WithDmdType alt_ty1 case_bndr' = annotateBndr env alt_ty case_bndr+ WithDmdType alt_ty1 case_bndr_dmd = findBndrDmd env alt_ty case_bndr+ !case_bndr' = setIdDemandInfo case_bndr case_bndr_dmd+ WithDmdType scrut_ty scrut' = dmdAnal env topSubDmd scrut -- NB: Base case is botDmdType, for empty case alternatives -- This is a unit for lubDmdType, and the right result -- when there really are no alternatives@@ -549,12 +556,30 @@ | WithDmdType rhs_ty rhs' <- dmdAnal env dmd rhs , WithDmdType alt_ty dmds <- findBndrsDmds env rhs_ty bndrs , let (_ :* case_bndr_sd) = findIdDemand alt_ty case_bndr- -- See Note [Demand on scrutinee of a product case]- id_dmds = addCaseBndrDmd case_bndr_sd dmds+ -- See Note [Demand on case-alternative binders]+ -- we can't use the scrut_sd, because it says 'Prod' and we'll use+ -- topSubDmd anyway for scrutinees of sum types.+ (!_scrut_sd, dmds') = addCaseBndrDmd case_bndr_sd dmds -- Do not put a thunk into the Alt- !new_ids = setBndrsDemandInfo bndrs id_dmds+ !new_ids = setBndrsDemandInfo bndrs dmds' = WithDmdType alt_ty (Alt con new_ids rhs') +-- Precondition: The SubDemand is not a Call+-- See Note [Demand on the scrutinee of a product case]+-- and Note [Demand on case-alternative binders]+addCaseBndrDmd :: SubDemand -- On the case binder+ -> [Demand] -- On the fields of the constructor+ -> (SubDemand, [Demand])+ -- SubDemand on the case binder incl. field demands+ -- and final demands for the components of the constructor+addCaseBndrDmd case_sd fld_dmds+ | Just (_, ds) <- viewProd (length fld_dmds) scrut_sd+ = (scrut_sd, ds)+ | otherwise+ = pprPanic "was a call demand" (ppr case_sd $$ ppr fld_dmds) -- See the Precondition+ where+ scrut_sd = case_sd `plusSubDmd` mkProd Unboxed fld_dmds+ {- Note [Analysing with absent demand] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@@ -674,6 +699,51 @@ x = (a, absent-error) and that'll crash. +Note [Demand on case-alternative binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The demand on a binder in a case alternative comes+ (a) From the demand on the binder itself+ (b) From the demand on the case binder+Forgetting (b) led directly to #10148.++Example. Source code:+ f x@(p,_) = if p then foo x else True++ foo (p,True) = True+ foo (p,q) = foo (q,p)++After strictness analysis, forgetting (b):+ f = \ (x_an1 [Dmd=1P(1L,ML)] :: (Bool, Bool)) ->+ case x_an1+ of wild_X7 [Dmd=MP(ML,ML)]+ { (p_an2 [Dmd=1L], ds_dnz [Dmd=A]) ->+ case p_an2 of _ {+ False -> GHC.Types.True;+ True -> foo wild_X7 }++Note that ds_dnz is syntactically dead, but the expression bound to it is+reachable through the case binder wild_X7. Now watch what happens if we inline+foo's wrapper:+ f = \ (x_an1 [Dmd=1P(1L,ML)] :: (Bool, Bool)) ->+ case x_an1+ of _ [Dmd=MP(ML,ML)]+ { (p_an2 [Dmd=1L], ds_dnz [Dmd=A]) ->+ case p_an2 of _ {+ False -> GHC.Types.True;+ True -> $wfoo_soq GHC.Types.True ds_dnz }++Look at that! ds_dnz has come back to life in the call to $wfoo_soq! A second+run of demand analysis would no longer infer ds_dnz to be absent.+But unlike occurrence analysis, which infers properties of the *syntactic*+shape of the program, the results of demand analysis describe expressions+*semantically* and are supposed to be mostly stable across Simplification.+That's why we should better account for (b).+In #10148, we ended up emitting a single-entry thunk instead of an updateable+thunk for a let binder that was an an absent case-alt binder during DmdAnal.++This is needed even for non-product types, in case the case-binder+is used but the components of the case alternative are not.+ Note [Aggregated demand for cardinality] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FIXME: This Note should be named [LetUp vs. LetDown] and probably predates@@ -725,43 +795,42 @@ ************************************************************************ -} -dmdTransform :: AnalEnv -- ^ The strictness environment- -> Id -- ^ The function- -> SubDemand -- ^ The demand on the function- -> DmdType -- ^ The demand type of the function in this context- -- Returned DmdEnv includes the demand on- -- this function plus demand on its free variables-+dmdTransform :: AnalEnv -- ^ The analysis environment+ -> Id -- ^ The variable+ -> SubDemand -- ^ The evaluation context of the var+ -> DmdType -- ^ The demand type unleashed by the variable in this+ -- context. The returned DmdEnv includes the demand on+ -- this function plus demand on its free variables -- See Note [What are demand signatures?] in "GHC.Types.Demand"-dmdTransform env var dmd+dmdTransform env var sd -- Data constructors | isDataConWorkId var- = dmdTransformDataConSig (idArity var) dmd+ = dmdTransformDataConSig (idArity var) sd -- Dictionary component selectors -- Used to be controlled by a flag. -- See #18429 for some perf measurements. | Just _ <- isClassOpId_maybe var- = -- pprTrace "dmdTransform:DictSel" (ppr var $$ ppr dmd) $- dmdTransformDictSelSig (idDmdSig var) dmd+ = -- pprTrace "dmdTransform:DictSel" (ppr var $$ ppr (idDmdSig var) $$ ppr sd) $+ dmdTransformDictSelSig (idDmdSig var) sd -- Imported functions | isGlobalId var- , let res = dmdTransformSig (idDmdSig var) dmd- = -- pprTrace "dmdTransform:import" (vcat [ppr var, ppr (idDmdSig var), ppr dmd, ppr res])+ , let res = dmdTransformSig (idDmdSig var) sd+ = -- pprTrace "dmdTransform:import" (vcat [ppr var, ppr (idDmdSig var), ppr sd, ppr res]) res -- Top-level or local let-bound thing for which we use LetDown ('useLetUp'). -- In that case, we have a strictness signature to unleash in our AnalEnv. | Just (sig, top_lvl) <- lookupSigEnv env var- , let fn_ty = dmdTransformSig sig dmd- = -- pprTrace "dmdTransform:LetDown" (vcat [ppr var, ppr sig, ppr dmd, ppr fn_ty]) $+ , let fn_ty = dmdTransformSig sig sd+ = -- pprTrace "dmdTransform:LetDown" (vcat [ppr var, ppr sig, ppr sd, ppr fn_ty]) $ case top_lvl of- NotTopLevel -> addVarDmd fn_ty var (C_11 :* dmd)+ NotTopLevel -> addVarDmd fn_ty var (C_11 :* sd) TopLevel | isInterestingTopLevelFn var -- Top-level things will be used multiple times or not at -- all anyway, hence the multDmd below: It means we don't -- have to track whether @var@ is used strictly or at most -- once, because ultimately it never will.- -> addVarDmd fn_ty var (C_0N `multDmd` (C_11 :* dmd)) -- discard strictness+ -> addVarDmd fn_ty var (C_0N `multDmd` (C_11 :* sd)) -- discard strictness | otherwise -> fn_ty -- don't bother tracking; just annotate with 'topDmd' later -- Everything else:@@ -769,8 +838,8 @@ -- * Lambda binders -- * Case and constructor field binders | otherwise- = -- pprTrace "dmdTransform:other" (vcat [ppr var, ppr sig, ppr dmd, ppr res]) $- unitDmdType (unitVarEnv var (C_11 :* dmd))+ = -- pprTrace "dmdTransform:other" (vcat [ppr var, ppr boxity, ppr sd]) $+ unitDmdType (unitVarEnv var (C_11 :* sd)) {- ********************************************************************* * *@@ -802,15 +871,21 @@ where rhs_arity = idArity id -- See Note [Demand signatures are computed for a threshold demand based on idArity]- rhs_dmd -- See Note [Demand analysis for join points]- -- See Note [Invariants on join points] invariant 2b, in GHC.Core- -- rhs_arity matches the join arity of the join point- | isJoinId id- = mkCalledOnceDmds rhs_arity let_dmd- | otherwise- = mkCalledOnceDmds rhs_arity topSubDmd - WithDmdType rhs_dmd_ty rhs' = dmdAnal env rhs_dmd rhs+ rhs_dmd = mkCalledOnceDmds rhs_arity body_dmd++ body_dmd+ | isJoinId id+ -- See Note [Demand analysis for join points]+ -- See Note [Invariants on join points] invariant 2b, in GHC.Core+ -- rhs_arity matches the join arity of the join point+ = let_dmd+ | otherwise+ -- See Note [Unboxed demand on function bodies returning small products]+ = unboxedWhenSmall (ae_opts env) (unboxableResultWidth env id) topSubDmd++ -- See Note [Do not unbox class dictionaries]+ WithDmdType rhs_dmd_ty rhs' = dmdAnal (adjustInlFun id env) rhs_dmd rhs DmdType rhs_fv rhs_dmds rhs_div = rhs_dmd_ty sig = mkDmdSigForArity rhs_arity (DmdType sig_fv rhs_dmds rhs_div)@@ -829,6 +904,7 @@ -- might turn into used-many even if the signature was stable and -- we'd have to do an additional iteration. reuseEnv makes sure that -- we never get used-once info for FVs of recursive functions.+ -- See #14816 where we try to get rid of reuseEnv. rhs_fv1 = case rec_flag of Recursive -> reuseEnv rhs_fv NonRecursive -> rhs_fv@@ -839,6 +915,26 @@ -- See Note [Lazy and unleashable free variables] !(!lazy_fv, !sig_fv) = partitionVarEnv isWeakDmd rhs_fv2 +unboxableResultWidth :: AnalEnv -> Id -> Maybe Arity+unboxableResultWidth env id+ | (pis,ret_ty) <- splitPiTys (idType id)+ , count (not . isNamedBinder) pis == idArity id+ , Just (tc, _tc_args, _co) <- normSplitTyConApp_maybe (ae_fam_envs env) ret_ty+ , Just dc <- tyConSingleAlgDataCon_maybe tc+ , null (dataConExTyCoVars dc) -- Can't unbox results with existentials+ = Just (dataConRepArity dc)+ | otherwise+ = Nothing++unboxedWhenSmall :: DmdAnalOpts -> Maybe Arity -> SubDemand -> SubDemand+-- See Note [Unboxed demand on function bodies returning small products]+unboxedWhenSmall opts mb_n sd+ | Just n <- mb_n+ , n <= dmd_unbox_width opts+ = unboxSubDemand sd+ | otherwise+ = sd+ -- | If given the (local, non-recursive) let-bound 'Id', 'useLetUp' determines -- whether we should process the binding up (body before rhs) or down (rhs -- before body).@@ -1056,34 +1152,6 @@ (since it is apparently Absent) and then inline (\x. fst g) we get disaster. But regardless, #18638 was a more complicated version of this, that actually happened in practice.--Historical Note [Product demands for function body]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-In 2013 I spotted this example, in shootout/binary_trees:-- Main.check' = \ b z ds. case z of z' { I# ip ->- case ds_d13s of- Main.Nil -> z'- Main.Node s14k s14l s14m ->- Main.check' (not b)- (Main.check' b- (case b {- False -> I# (-# s14h s14k);- True -> I# (+# s14h s14k)- })- s14l)- s14m } } }--Here we *really* want to unbox z, even though it appears to be used boxed in-the Nil case. Partly the Nil case is not a hot path. But more specifically,-the whole function gets the CPR property if we do.--That motivated using a demand of C1(C1(C1(P(L,L)))) for the RHS, where-(solely because the result was a product) we used a product demand-(albeit with lazy components) for the body. But that gives very silly-behaviour -- see #17932. Happily it turns out now to be entirely-unnecessary: we get good results with C1(C1(C1(L))). So I simply-deleted the special case. -} {- *********************************************************************@@ -1159,7 +1227,6 @@ {- Note [Safe abortion in the fixed-point iteration] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~- Fixed-point iteration may fail to terminate. But we cannot simply give up and return the environment and code unchanged! We still need to do one additional round, for two reasons:@@ -1231,9 +1298,12 @@ unitDmdType dmd_env = DmdType dmd_env [] topDiv coercionDmdEnv :: Coercion -> DmdEnv-coercionDmdEnv co = mapVarEnv (const topDmd) (getUniqSet $ coVarsOfCo co)- -- The VarSet from coVarsOfCo is really a VarEnv Var+coercionDmdEnv co = coercionsDmdEnv [co] +coercionsDmdEnv :: [Coercion] -> DmdEnv+coercionsDmdEnv cos = mapVarEnv (const topDmd) (getUniqSet $ coVarsOfCos cos)+ -- The VarSet from coVarsOfCos is really a VarEnv Var+ addVarDmd :: DmdType -> Var -> Demand -> DmdType addVarDmd (DmdType fv ds res) var dmd = DmdType (extendVarEnv_C plusDmd fv var dmd) ds res@@ -1283,18 +1353,6 @@ setBndrsDemandInfo [] ds = assert (null ds) [] setBndrsDemandInfo bs _ = pprPanic "setBndrsDemandInfo" (ppr bs) -annotateBndr :: AnalEnv -> DmdType -> Var -> WithDmdType Var--- The returned env has the var deleted--- The returned var is annotated with demand info--- according to the result demand of the provided demand type--- No effect on the argument demands-annotateBndr env dmd_ty var- | isId var = WithDmdType dmd_ty' new_id- | otherwise = WithDmdType dmd_ty var- where- new_id = setIdDemandInfo var dmd- WithDmdType dmd_ty' dmd = findBndrDmd env dmd_ty var- annotateLamIdBndr :: AnalEnv -> DmdType -- Demand type of body -> Id -- Lambda binder@@ -1308,8 +1366,11 @@ -- pprTrace "annLamBndr" (vcat [ppr id, ppr dmd_ty, ppr final_ty]) $ WithDmdType main_ty new_id where- new_id = setIdDemandInfo id dmd- main_ty = addDemand dmd dmd_ty'+ -- See Note [Finalising boxity for demand signature] in "GHC.Core.Opt.WorkWrap.Utils"+ -- and Note [Do not unbox class dictionaries]+ dmd' = finaliseBoxity (ae_fam_envs env) (ae_inl_fun env) (idType id) dmd+ new_id = setIdDemandInfo id dmd'+ main_ty = addDemand dmd' dmd_ty' WithDmdType dmd_ty' dmd = findBndrDmd env dmd_ty id {- Note [NOINLINE and strictness]@@ -1389,11 +1450,14 @@ data AnalEnv = AE- { ae_strict_dicts :: !Bool -- ^ Enable strict dict- , ae_sigs :: !SigEnv- , ae_virgin :: !Bool -- ^ True on first iteration only- -- See Note [Initialising strictness]- , ae_fam_envs :: !FamInstEnvs+ { ae_opts :: !DmdAnalOpts -- ^ Analysis options+ , ae_sigs :: !SigEnv+ , ae_virgin :: !Bool -- ^ True on first iteration only+ -- See Note [Initialising strictness]+ , ae_fam_envs :: !FamInstEnvs+ , ae_inl_fun :: !InsideInlineableFun+ -- ^ Whether we analyse the body of an inlineable fun.+ -- See Note [Do not unbox class dictionaries]. } -- We use the se_env to tell us whether to@@ -1408,16 +1472,16 @@ instance Outputable AnalEnv where ppr env = text "AE" <+> braces (vcat [ text "ae_virgin =" <+> ppr (ae_virgin env)- , text "ae_strict_dicts =" <+> ppr (ae_strict_dicts env) , text "ae_sigs =" <+> ppr (ae_sigs env) ]) emptyAnalEnv :: DmdAnalOpts -> FamInstEnvs -> AnalEnv emptyAnalEnv opts fam_envs- = AE { ae_strict_dicts = dmd_strict_dicts opts+ = AE { ae_opts = opts , ae_sigs = emptySigEnv , ae_virgin = True , ae_fam_envs = fam_envs+ , ae_inl_fun = NotInsideInlineableFun } emptySigEnv :: SigEnv@@ -1445,6 +1509,13 @@ nonVirgin :: AnalEnv -> AnalEnv nonVirgin env = env { ae_virgin = False } +-- | Sets 'ae_inl_fun' according to whether the given 'Id' has an inlineable+-- unfolding. See Note [Do not unbox class dictionaries].+adjustInlFun :: Id -> AnalEnv -> AnalEnv+adjustInlFun id env+ | isStableUnfolding (realIdUnfolding id) = env { ae_inl_fun = InsideInlineableFun }+ | otherwise = env { ae_inl_fun = NotInsideInlineableFun }+ findBndrsDmds :: AnalEnv -> DmdType -> [Var] -> WithDmdType [Demand] -- Return the demands on the Ids in the [Var] findBndrsDmds env dmd_ty bndrs@@ -1472,9 +1543,9 @@ strictify dmd -- See Note [Making dictionaries strict]- | ae_strict_dicts env+ | dmd_strict_dicts (ae_opts env) -- We never want to strictify a recursive let. At the moment- -- annotateBndr is only call for non-recursive lets; if that+ -- findBndrDmd is never called for recursive lets; if that -- changes, we need a RecFlag parameter and another guard here. = strictifyDictDmd id_ty dmd | otherwise@@ -1522,7 +1593,7 @@ of a difference to stop a function from inlining. This is documented in #18421. -It's somewhat similar to Note [Do not unpack class dictionaries] although+It's somewhat similar to Note [Do not unbox class dictionaries] although here our problem is with the inliner, not the specializer. Note [Initialising strictness]
compiler/GHC/Core/Opt/Pipeline.hs view
@@ -514,7 +514,7 @@ updateBindsM (liftIO . cprAnalProgram logger fam_envs) CoreDoWorkerWrapper -> {-# SCC "WorkWrap" #-}- updateBinds (wwTopBinds dflags fam_envs us)+ updateBinds (wwTopBinds (mg_module guts) dflags fam_envs us) CoreDoSpecialising -> {-# SCC "Specialise" #-} specProgram guts@@ -1067,6 +1067,7 @@ dmdAnal logger dflags fam_envs rules binds = do let !opts = DmdAnalOpts { dmd_strict_dicts = gopt Opt_DictsStrict dflags+ , dmd_unbox_width = dmdUnboxWidth dflags } binds_plus_dmds = dmdAnalProgram opts fam_envs rules binds Logger.putDumpFileMaybe logger Opt_D_dump_str_signatures "Strictness signatures" FormatText $
compiler/GHC/Core/Opt/SetLevels.hs view
@@ -82,7 +82,6 @@ import GHC.Core.Utils ( exprType, exprIsHNF , exprOkForSpeculation , exprIsTopLevelBindable- , isExprLevPoly , collectMakeStaticArgs , mkLamTypes )@@ -91,7 +90,9 @@ import GHC.Core.Subst import GHC.Core.Make ( sortQuantVars ) import GHC.Core.Type ( Type, splitTyConApp_maybe, tyCoVarsOfType- , mightBeUnliftedType, closeOverKindsDSet )+ , mightBeUnliftedType, closeOverKindsDSet+ , typeHasFixedRuntimeRep+ ) import GHC.Core.Multiplicity ( pattern Many ) import GHC.Core.DataCon ( dataConOrigResTy ) @@ -290,35 +291,35 @@ -> [LevelledBind] setLevels float_lams binds us- = initLvl us (do_them init_env binds)+ = initLvl us (do_them binds) where- init_env = initialEnv float_lams+ env = initialEnv float_lams binds - do_them :: LevelEnv -> [CoreBind] -> LvlM [LevelledBind]- do_them _ [] = return []- do_them env (b:bs)- = do { (lvld_bind, env') <- lvlTopBind env b- ; lvld_binds <- do_them env' bs+ do_them :: [CoreBind] -> LvlM [LevelledBind]+ do_them [] = return []+ do_them (b:bs)+ = do { lvld_bind <- lvlTopBind env b+ ; lvld_binds <- do_them bs ; return (lvld_bind : lvld_binds) } -lvlTopBind :: LevelEnv -> Bind Id -> LvlM (LevelledBind, LevelEnv)+lvlTopBind :: LevelEnv -> Bind Id -> LvlM LevelledBind lvlTopBind env (NonRec bndr rhs)- = do { rhs' <- lvl_top env NonRecursive bndr rhs- ; let (env', [bndr']) = substAndLvlBndrs NonRecursive env tOP_LEVEL [bndr]- ; return (NonRec bndr' rhs', env') }+ = do { (bndr', rhs') <- lvl_top env NonRecursive bndr rhs+ ; return (NonRec bndr' rhs') } lvlTopBind env (Rec pairs)- = do { let (env', bndrs') = substAndLvlBndrs Recursive env tOP_LEVEL- (map fst pairs)- ; rhss' <- mapM (\(b,r) -> lvl_top env' Recursive b r) pairs- ; return (Rec (bndrs' `zip` rhss'), env') }+ = do { prs' <- mapM (\(b,r) -> lvl_top env Recursive b r) pairs+ ; return (Rec prs') } -lvl_top :: LevelEnv -> RecFlag -> Id -> CoreExpr -> LvlM LevelledExpr+lvl_top :: LevelEnv -> RecFlag -> Id -> CoreExpr+ -> LvlM (LevelledBndr, LevelledExpr)+-- NB: 'env' has all the top-level binders in scope, so+-- there is no need call substAndLvlBndrs here lvl_top env is_rec bndr rhs- = lvlRhs env is_rec- (isDeadEndId bndr)- Nothing -- Not a join point- (freeVars rhs)+ = do { rhs' <- lvlRhs env is_rec (isDeadEndId bndr)+ Nothing -- Not a join point+ (freeVars rhs)+ ; return (stayPut tOP_LEVEL bndr, rhs') } {- ************************************************************************@@ -668,8 +669,9 @@ -- Only floating to the top level is allowed. || hasFreeJoin env fvs -- If there is a free join, don't float -- See Note [Free join points]- || isExprLevPoly expr- -- We can't let-bind representation-polymorphic expressions+ || not (typeHasFixedRuntimeRep (exprType expr))+ -- We can't let-bind an expression if we don't know+ -- how it will be represented at runtime. -- See Note [Representation polymorphism invariants] in GHC.Core || notWorthFloating expr abs_vars || not float_me@@ -1553,9 +1555,9 @@ {- Note [le_subst and le_env] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-We clone let- and case-bound variables so that they are still distinct-when floated out; hence the le_subst/le_env. (see point 3 of the-module overview comment). We also use these envs when making a+We clone nested let- and case-bound variables so that they are still+distinct when floated out; hence the le_subst/le_env. (see point 3 of+the module overview comment). We also use these envs when making a variable polymorphic because we want to float it out past a big lambda. @@ -1582,14 +1584,21 @@ The domain of the le_lvl_env is the *post-cloned* Ids -} -initialEnv :: FloatOutSwitches -> LevelEnv-initialEnv float_lams- = LE { le_switches = float_lams- , le_ctxt_lvl = tOP_LEVEL+initialEnv :: FloatOutSwitches -> CoreProgram -> LevelEnv+initialEnv float_lams binds+ = LE { le_switches = float_lams+ , le_ctxt_lvl = tOP_LEVEL , le_join_ceil = panic "initialEnv"- , le_lvl_env = emptyVarEnv- , le_subst = emptySubst- , le_env = emptyVarEnv }+ , le_lvl_env = emptyVarEnv+ , le_subst = mkEmptySubst in_scope_toplvl+ , le_env = emptyVarEnv }+ where+ in_scope_toplvl = emptyInScopeSet `extendInScopeSetList` bindersOfBinds binds+ -- The Simplifier (see Note [Glomming] in GHC.Core.Opt.Occuranal) and+ -- the specialiser (see Note [Top level scope] in GHC.Core.Opt.Specialise)+ -- may both produce top-level bindings where an early binding refers+ -- to a later one. So here we put all the top-level binders in scope before+ -- we start, to satisfy the lookupIdSubst invariants (#20200 and #20294) addLvl :: Level -> VarEnv Level -> OutVar -> VarEnv Level addLvl dest_lvl env v' = extendVarEnv env v' dest_lvl
compiler/GHC/Core/Opt/Simplify.hs view
@@ -51,8 +51,7 @@ import GHC.Types.Id.Make ( seqId ) import GHC.Types.Id.Info import GHC.Types.Name ( mkSystemVarName, isExternalName, getOccFS )-import GHC.Types.Demand ( DmdSig(..), Demand, dmdTypeDepth, isStrUsedDmd- , mkClosedDmdSig, topDmd, seqDmd, isDeadEndDiv )+import GHC.Types.Demand import GHC.Types.Cpr ( mkCprSig, botCpr ) import GHC.Types.Unique ( hasKey ) import GHC.Types.Basic@@ -435,9 +434,8 @@ ; completeNonRecX NotTopLevel env' (isStrictId bndr') bndr bndr' new_rhs } -- NotTopLevel: simplNonRecX is only used for NotTopLevel things --- -- isStrictId: use bndr' because in a representation-polymorphic- -- setting, the InId bndr might have a representation-polymorphic- -- type, which isStrictId doesn't expect+ -- isStrictId: use bndr' because the InId bndr might not have+ -- a fixed runtime representation, which isStrictId doesn't expect -- c.f. Note [Dark corner with representation polymorphism] --------------------------@@ -950,12 +948,7 @@ info2 = info1 `setUnfoldingInfo` new_unf -- Demand info: Note [Setting the demand info]- -- We also have to nuke demand info if for some reason- -- eta-expansion *reduces* the arity of the binding to less- -- than that of the strictness sig. This can happen: see Note [Arity decrease]. info3 | isEvaldUnfolding new_unf- || (case dmdSigInfo info2 of- DmdSig dmd_ty -> new_arity < dmdTypeDepth dmd_ty) = zapDemandInfo info2 `orElse` info2 | otherwise = info2@@ -974,31 +967,8 @@ info5 = zapCallArityInfo info4 -{- Note [Arity decrease]-~~~~~~~~~~~~~~~~~~~~~~~~-Generally speaking the arity of a binding should not decrease. But it *can*-legitimately happen because of RULES. Eg- f = g @Int-where g has arity 2, will have arity 2. But if there's a rewrite rule- g @Int --> h-where h has arity 1, then f's arity will decrease. Here's a real-life example,-which is in the output of Specialise:-- Rec {- $dm {Arity 2} = \d.\x. op d- {-# RULES forall d. $dm Int d = $s$dm #-}-- dInt = MkD .... opInt ...- opInt {Arity 1} = $dm dInt-- $s$dm {Arity 0} = \x. op dInt }--Here opInt has arity 1; but when we apply the rule its arity drops to 0.-That's why Specialise goes to a little trouble to pin the right arity-on specialised functions too.--Note [Bottoming bindings]-~~~~~~~~~~~~~~~~~~~~~~~~~+{- Note [Bottoming bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Suppose we have let x = error "urk" in ...(case x of <alts>)...@@ -1572,7 +1542,7 @@ addCoerce co cont@(ApplyToVal { sc_arg = arg, sc_env = arg_se , sc_dup = dup, sc_cont = tail }) | Just (m_co1, m_co2) <- pushCoValArg co- , levity_ok m_co1+ , fixed_rep m_co1 = {-#SCC "addCoerce-pushCoValArg" #-} do { tail' <- addCoerceM m_co2 tail ; case m_co1 of {@@ -1600,10 +1570,11 @@ -- See Note [Optimising reflexivity] | otherwise = return (CastIt co cont) - levity_ok :: MCoercionR -> Bool- levity_ok MRefl = True- levity_ok (MCo co) = not $ isTypeLevPoly $ coercionRKind co- -- Without this check, we get a lev-poly arg+ fixed_rep :: MCoercionR -> Bool+ fixed_rep MRefl = True+ fixed_rep (MCo co) = typeHasFixedRuntimeRep $ coercionRKind co+ -- Without this check, we can get an argument which does not+ -- have a fixed runtime representation. -- See Note [Representation polymorphism invariants] in GHC.Core -- test: typecheck/should_run/EtaExpandLevPoly @@ -1746,10 +1717,10 @@ ; return (floats1 `addFloats` floats2, expr') } {- Note [Dark corner with representation polymorphism]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In `simplNonRecE`, the call to `isStrictId` will fail if the binder-has a representation-polymorphic type, of kind (TYPE r). So we are careful to-call `isStrictId` on the OutId, not the InId, in case we have+does not have a fixed runtime representation, e.g. if it is of kind (TYPE r).+So we are careful to call `isStrictId` on the OutId, not the InId, in case we have ((\(r::RuntimeRep) \(x::TYPE r). blah) Lifted arg) That will lead to `simplNonRecE env (x::TYPE r) arg`, and we can't tell if x is lifted or unlifted from that.@@ -1765,7 +1736,7 @@ care here. Note [Avoiding exponential behaviour]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ One way in which we can get exponential behaviour is if we simplify a big expression, and the re-simplify it -- and then this happens in a deeply-nested way. So we must be jolly careful about re-simplifying
compiler/GHC/Core/Opt/SpecConstr.hs view
@@ -1806,7 +1806,7 @@ go_one env d (Var v) = extendVarEnv_C plusDmd env v d go_one env (_n :* cd) e -- NB: _n does not have to be strict | (Var _, args) <- collectArgs e- , Just ds <- viewProd (length args) cd+ , Just (_b, ds) <- viewProd (length args) cd -- TODO: We may want to look at boxity _b, though... = go env ds args go_one env _ _ = env
compiler/GHC/Core/Opt/WorkWrap.hs view
@@ -13,13 +13,12 @@ import GHC.Core.Opt.Arity ( manifestArity ) import GHC.Core-import GHC.Core.Unfold import GHC.Core.Unfold.Make import GHC.Core.Utils ( exprType, exprIsHNF ) import GHC.Core.Type import GHC.Core.Opt.WorkWrap.Utils import GHC.Core.FamInstEnv-import GHC.Core.SimpleOpt( SimpleOpts(..) )+import GHC.Core.SimpleOpt import GHC.Types.Var import GHC.Types.Id@@ -37,6 +36,7 @@ import GHC.Utils.Panic.Plain import GHC.Utils.Monad import GHC.Utils.Trace+import GHC.Unit.Types {- We take Core bindings whose binders have:@@ -66,14 +66,14 @@ \end{enumerate} -} -wwTopBinds :: DynFlags -> FamInstEnvs -> UniqSupply -> CoreProgram -> CoreProgram+wwTopBinds :: Module -> DynFlags -> FamInstEnvs -> UniqSupply -> CoreProgram -> CoreProgram -wwTopBinds dflags fam_envs us top_binds+wwTopBinds this_mod dflags fam_envs us top_binds = initUs_ us $ do top_binds' <- mapM (wwBind ww_opts) top_binds return (concat top_binds') where- ww_opts = initWwOpts dflags fam_envs+ ww_opts = initWwOpts this_mod dflags fam_envs {- ************************************************************************@@ -390,9 +390,21 @@ in case z of A -> j 1 2 B -> j 2 3 -Note that we still want to give @j@ the CPR property, so that @f@ has it. So+Note that we still want to give `j` the CPR property, so that `f` has it. So CPR *analyse* join points as regular functions, but don't *transform* them. +We could retain the CPR /signature/ on the worker after W/W, but it would+become outright wrong if the Simplifier pushes a non-trivial continuation+into it. For example:+ case (let $j x = (x,x) in ...) of alts+ ==>+ let $j x = case (x,x) of alts in case ... of alts+Before pushing the case in, `$j` has the CPR property, but not afterwards.++So we simply zap the CPR signature for join pints as part of the W/W pass.+The signature served its purpose during CPR analysis in propagating the+CPR property of `$j`.+ Doing W/W for returned products on a join point would be tricky anyway, as the worker could not be a join point because it would not be tail-called. However, doing the *argument* part of W/W still works for join points, since the wrapper@@ -529,7 +541,7 @@ = return [ (new_fn_id, rhs ) ] | is_fun && is_eta_exp- = splitFun ww_opts new_fn_id fn_info rhs+ = splitFun ww_opts new_fn_id rhs -- See Note [Thunk splitting] | isNonRec is_rec, is_thunk@@ -541,11 +553,17 @@ where fn_info = idInfo fn_id (wrap_dmds, _) = splitDmdSig (dmdSigInfo fn_info)+ new_fn_id = zap_join_cpr $ zap_usage fn_id - new_fn_id = zapIdUsedOnceInfo (zapIdUsageEnvInfo fn_id)+ zap_usage = zapIdUsedOnceInfo . zapIdUsageEnvInfo -- See Note [Zapping DmdEnv after Demand Analyzer] and -- See Note [Zapping Used Once info in WorkWrap] + zap_join_cpr id+ | isJoinId id = id `setIdCprSig` topCprSig+ | otherwise = id+ -- See Note [Don't w/w join points for CPR]+ -- is_eta_exp: see Note [Don't eta expand in w/w] is_eta_exp = length wrap_dmds == manifestArity rhs is_fun = notNull wrap_dmds || isJoinId fn_id@@ -690,17 +708,19 @@ ----------------------splitFun :: WwOpts -> Id -> IdInfo -> CoreExpr -> UniqSM [(Id, CoreExpr)]-splitFun ww_opts fn_id fn_info rhs+splitFun :: WwOpts -> Id -> CoreExpr -> UniqSM [(Id, CoreExpr)]+splitFun ww_opts fn_id rhs = warnPprTrace (not (wrap_dmds `lengthIs` (arityInfo fn_info))) (ppr fn_id <+> (ppr wrap_dmds $$ ppr cpr)) $- do { mb_stuff <- mkWwBodies ww_opts fn_id arg_vars (exprType body) wrap_dmds use_cpr_info+ do { mb_stuff <- mkWwBodies ww_opts fn_id arg_vars (exprType body) wrap_dmds cpr ; case mb_stuff of Nothing -> -- No useful wrapper; leave the binding alone return [(fn_id, rhs)] Just stuff- | Just stable_unf <- certainlyWillInline uf_opts fn_info+ | let opt_wwd_rhs = simpleOptExpr (wo_simple_opts ww_opts) rhs+ -- We need to stabilise the WW'd (and optimised) RHS below+ , Just stable_unf <- certainlyWillInline uf_opts fn_info opt_wwd_rhs -- We could make a w/w split, but in fact the RHS is small -- See Note [Don't w/w inline small non-loop-breaker things] , let id_w_unf = fn_id `setIdUnfolding` stable_unf@@ -710,12 +730,11 @@ | otherwise -> do { work_uniq <- getUniqueM ; return (mkWWBindPair ww_opts fn_id fn_info arg_vars body- work_uniq div cpr stuff) } }+ work_uniq div stuff) } } where uf_opts = so_uf_opts (wo_simple_opts ww_opts)+ fn_info = idInfo fn_id (arg_vars, body) = collectBinders rhs- -- collectBinders was not enough for GHC.Event.IntTable.insertWith- -- last time I checked, where manifest lambdas were wrapped in casts (wrap_dmds, div) = splitDmdSig (dmdSigInfo fn_info) @@ -727,17 +746,11 @@ <+> text "arityInfo:" <+> ppr (arityInfo fn_info)) $ ct_cpr cpr_ty - -- use_cpr_info is the CPR we w/w for. Note that we kill it for join points,- -- see Note [Don't w/w join points for CPR].- use_cpr_info | isJoinId fn_id = topCpr- | otherwise = cpr-- mkWWBindPair :: WwOpts -> Id -> IdInfo- -> [Var] -> CoreExpr -> Unique -> Divergence -> Cpr+ -> [Var] -> CoreExpr -> Unique -> Divergence -> ([Demand], JoinArity, Id -> CoreExpr, Expr CoreBndr -> CoreExpr) -> [(Id, CoreExpr)]-mkWWBindPair ww_opts fn_id fn_info fn_args fn_body work_uniq div cpr+mkWWBindPair ww_opts fn_id fn_info fn_args fn_body work_uniq div (work_demands, join_arity, wrap_fn, work_fn) = [(work_id, work_rhs), (wrap_id, wrap_rhs)] -- Worker first, because wrapper mentions it@@ -783,7 +796,7 @@ -- Even though we may not be at top level, -- it's ok to give it an empty DmdEnv - `setIdCprSig` mkCprSig work_arity work_cpr_info+ `setIdCprSig` topCprSig `setIdDemandInfo` worker_demand @@ -814,13 +827,6 @@ fn_inline_spec = inl_inline fn_inl_prag fn_unfolding = realUnfoldingInfo fn_info - -- Even if we don't w/w join points for CPR, we might still do so for- -- strictness. In which case a join point worker keeps its original CPR- -- property; see Note [Don't w/w join points for CPR]. Otherwise, the worker- -- doesn't have the CPR property anymore.- work_cpr_info | isJoinId fn_id = cpr- | otherwise = topCpr- mkStrWrapperInlinePrag :: InlinePragma -> InlinePragma mkStrWrapperInlinePrag (InlinePragma { inl_act = act, inl_rule = rule_info }) = InlinePragma { inl_src = SourceText "{-# INLINE"@@ -971,8 +977,7 @@ splitThunk ww_opts is_rec x rhs = assert (not (isJoinId x)) $ do { let x' = localiseId x -- See comment above- ; (useful,_, wrap_fn, fn_arg)- <- mkWWstr_one ww_opts NotArgOfInlineableFun x'+ ; (useful,_, wrap_fn, fn_arg) <- mkWWstr_one ww_opts x' ; let res = [ (x, Let (NonRec x' rhs) (wrap_fn fn_arg)) ] ; if useful then assertPpr (isNonRec is_rec) (ppr x) -- The thunk must be non-recursive return res
compiler/GHC/Core/Opt/WorkWrap/Utils.hs view
@@ -10,8 +10,9 @@ module GHC.Core.Opt.WorkWrap.Utils ( WwOpts(..), initWwOpts, mkWwBodies, mkWWstr, mkWWstr_one, mkWorkerArgs , DataConPatContext(..)- , UnboxingDecision(..), ArgOfInlineableFun(..), wantToUnboxArg- , findTypeShape, mkAbsentFiller, IsRecDataConResult(..), isRecDataCon+ , UnboxingDecision(..), InsideInlineableFun(..), wantToUnboxArg+ , findTypeShape, IsRecDataConResult(..), isRecDataCon, finaliseBoxity+ , mkAbsentFiller , isWorkerSmallEnough ) where@@ -64,6 +65,7 @@ import Data.List ( unzip4 ) import GHC.Types.RepType+import GHC.Unit.Types {- ************************************************************************@@ -141,17 +143,18 @@ , wo_cpr_anal :: !Bool , wo_fun_to_thunk :: !Bool , wo_max_worker_args :: !Int- , wo_output_file :: Maybe String+ -- Used for absent argument error message+ , wo_module :: !Module } -initWwOpts :: DynFlags -> FamInstEnvs -> WwOpts-initWwOpts dflags fam_envs = MkWwOpts+initWwOpts :: Module -> DynFlags -> FamInstEnvs -> WwOpts+initWwOpts this_mod dflags fam_envs = MkWwOpts { wo_fam_envs = fam_envs , wo_simple_opts = initSimpleOpts dflags , wo_cpr_anal = gopt Opt_CprAnal dflags , wo_fun_to_thunk = gopt Opt_FunToThunk dflags , wo_max_worker_args = maxWorkerArgs dflags- , wo_output_file = outputFile dflags+ , wo_module = this_mod } type WwResult@@ -227,7 +230,7 @@ res_ty' = GHC.Core.Subst.substTy subst res_ty ; (useful1, work_args, wrap_fn_str, fn_args)- <- mkWWstr opts inlineable_flag cloned_arg_vars+ <- mkWWstr opts cloned_arg_vars -- Do CPR w/w. See Note [Always do CPR w/w] ; (useful2, wrap_fn_cpr, work_fn_cpr, cpr_res_ty)@@ -263,9 +266,6 @@ = info `setOccInfo` noOccInfo mb_join_arity = isJoinId_maybe fun_id- inlineable_flag -- See Note [Do not unpack class dictionaries]- | isStableUnfolding (realIdUnfolding fun_id) = MaybeArgOfInlineableFun- | otherwise = NotArgOfInlineableFun -- Note [Do not split void functions] only_one_void_argument@@ -560,60 +560,31 @@ -- The @[s]@ carries the bits of information with which we can continue -- unboxing, e.g. @s@ will be 'Demand' or 'Cpr'. --- | A specialised Bool for an argument to 'wantToUnboxArg'.--- See Note [Do not unpack class dictionaries].-data ArgOfInlineableFun- = NotArgOfInlineableFun -- ^ Definitely not in an inlineable fun.- | MaybeArgOfInlineableFun -- ^ We might be in an inlineable fun, so we won't- -- unbox dictionary args.- deriving Eq---- | Unboxing strategy for strict arguments.-wantToUnboxArg :: FamInstEnvs -> ArgOfInlineableFun -> Type -> Demand -> UnboxingDecision Demand+-- | Unwraps the 'Boxity' decision encoded in the given 'SubDemand' and returns+-- a 'DataConPatContext' as well the nested demands on fields of the 'DataCon'+-- to unbox.+wantToUnboxArg+ :: FamInstEnvs+ -> Type -- ^ Type of the argument+ -> Demand -- ^ How the arg was used+ -> UnboxingDecision Demand -- See Note [Which types are unboxed?]-wantToUnboxArg fam_envs inlineable_flag ty dmd- | isAbsDmd dmd+wantToUnboxArg fam_envs ty (n :* sd)+ | isAbs n = DropAbsent - | isStrUsedDmd dmd- , Just (tc, tc_args, co) <- normSplitTyConApp_maybe fam_envs ty+ | Just (tc, tc_args, co) <- normSplitTyConApp_maybe fam_envs ty , Just dc <- tyConSingleAlgDataCon_maybe tc , let arity = dataConRepArity dc- -- See Note [Unpacking arguments with product and polymorphic demands]- , Just cs <- split_prod_dmd_arity dmd arity- -- See Note [Do not unpack class dictionaries]- , inlineable_flag == NotArgOfInlineableFun || not (isClassPred ty)- -- See Note [mkWWstr and unsafeCoerce]- , cs `lengthIs` arity- -- See Note [Add demands for strict constructors]- , let cs' = addDataConStrictness dc cs- = Unbox (DataConPatContext dc tc_args co) cs'+ , Just (Unboxed, ds) <- viewProd arity sd -- See Note [Boxity Analysis]+ -- NB: No strictness or evaluatedness checks here. That is done by+ -- 'finaliseBoxity'!+ = Unbox (DataConPatContext dc tc_args co) ds | otherwise = StopUnboxing - where- split_prod_dmd_arity dmd arity- -- For seqDmd, it should behave like <S(AAAA)>, for some- -- suitable arity- | isSeqDmd dmd = Just (replicate arity absDmd)- | _ :* Prod ds <- dmd = Just ds- | otherwise = Nothing -addDataConStrictness :: DataCon -> [Demand] -> [Demand]--- See Note [Add demands for strict constructors]-addDataConStrictness con ds- | Nothing <- dataConWrapId_maybe con- -- DataCon worker=wrapper. Implies no strict fields, so nothing to do- = ds-addDataConStrictness con ds- = zipWithEqual "addDataConStrictness" add ds strs- where- strs = dataConRepStrictness con- add dmd str | isMarkedStrict str = strictifyDmd dmd- | otherwise = dmd-- -- | Unboxing strategy for constructed results. wantToUnboxResult :: FamInstEnvs -> Type -> Cpr -> UnboxingDecision Cpr -- See Note [Which types are unboxed?]@@ -686,35 +657,8 @@ constraints, type classes etc. So it can be GADT. These evidence arguments are simply value arguments, and should not get in the way. -Note [Unpacking arguments with product and polymorphic demands]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-The argument is unpacked in a case if it has a product type and has a-strict *and* used demand put on it. I.e., arguments, with demands such-as the following ones:-- <S,U(U, L)>- <S(L,S),U>--will be unpacked, but-- <S,U> or <B,U>--will not, because the pieces aren't used. This is quite important otherwise-we end up unpacking massive tuples passed to the bottoming function. Example:-- f :: ((Int,Int) -> String) -> (Int,Int) -> a- f g pr = error (g pr)-- main = print (f fst (1, error "no"))--Does 'main' print "error 1" or "error no"? We don't really want 'f'-to unbox its second argument. This actually happened in GHC's onwn-source code, in Packages.applyPackageFlag, which ended up un-boxing-the enormous DynFlags tuple, and being strict in the-as-yet-un-filled-in unitState files.--Note [Do not unpack class dictionaries]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Note [Do not unbox class dictionaries]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If we have f :: Ord a => [a] -> Int -> a {-# INLINABLE f #-}@@ -727,12 +671,19 @@ fw :: (a->a->Bool) -> [a] -> Int# -> a and the type-class specialiser can't specialise that. An example is #6056. -But in any other situation a dictionary is just an ordinary value,-and can be unpacked. So we track the INLINABLE pragma, and switch-off the unpacking in mkWWstr_one (see the isClassPred test).+But in any other situation, a dictionary is just an ordinary value,+and can be unpacked. So we track the INLINABLE pragma, and discard the boxity+flag in finaliseBoxity (see the isClassPred test). Historical note: #14955 describes how I got this fix wrong the first time. +Note that the simplicity of this fix implies that INLINE functions (such as+wrapper functions after the WW run) will never say that they unbox class+dictionaries. That's not ideal, but not worth losing sleep over, as INLINE+functions will have been inlined by the time we run demand analysis so we'll+see the unboxing around the worker in client modules. I got aware of the issue+in T5075 by the change in boxity of loop between demand analysis runs.+ Note [mkWWstr and unsafeCoerce] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By using unsafeCoerce, it is possible to make the number of demands fail to@@ -740,14 +691,14 @@ If so, the worker/wrapper split doesn't work right and we get a Core Lint bug. The fix here is simply to decline to do w/w if that happens. -Note [Add demands for strict constructors]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Note [Unboxing evaluated arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Consider this program (due to Roman): data X a = X !a foo :: X Int -> Int -> Int- foo (X a) n = go 0+ foo x@(X a) n = go 0 where go i | i < n = a + go (i+1) | otherwise = 0@@ -756,12 +707,12 @@ $wfoo :: Int# -> Int# -> Int# -with the first argument unboxed, so that it is not eval'd each time-around the 'go' loop (which would otherwise happen, since 'foo' is not-strict in 'a'). It is sound for the wrapper to pass an unboxed arg-because X is strict, so its argument must be evaluated. And if we-*don't* pass an unboxed argument, we can't even repair it by adding a-`seq` thus:+with the first argument unboxed, so that it is not eval'd each time around the+'go' loop (which would otherwise happen, since 'foo' is not strict in 'a'). It+is sound for the wrapper to pass an unboxed arg because X is strict+(see Note [Strictness and Unboxing] in "GHC.Core.Opt.DmdAnal"), so its argument+must be evaluated. And if we *don't* pass an unboxed argument, we can't even+repair it by adding a `seq` thus: foo (X a) n = a `seq` go 0 @@ -769,34 +720,38 @@ So here's what we do -* We leave the demand-analysis alone. The demand on 'a' in the- definition of 'foo' is <L, U(U)>; the strictness info is Lazy- because foo's body may or may not evaluate 'a'; but the usage info- says that 'a' is unpacked and its content is used.+* Since this has nothing to do with how 'foo' uses 'a', we leave demand analysis+ alone, but account for the additional evaluatedness when annotating the binder+ in 'annotateLamIdBndr' via 'finaliseBoxity', which will retain the Unboxed boxity+ on 'a' in the definition of 'foo' in the demand 'L!P(L)'; meaning it's used+ lazily but unboxed nonetheless. This seems to contradict+ Note [No lazy, Unboxed demands in demand signature], but we know that 'a' is+ evaluated and thus can be unboxed. -* During worker/wrapper, if we unpack a strict constructor (as we do- for 'foo'), we use 'addDataConStrictness' to bump up the strictness on- the strict arguments of the data constructor.+* When 'finaliseBoxity' decides to unbox a record, it will zip the field demands+ together with the respective 'StrictnessMark'. In case of 'x', it will pair+ up the lazy field demand 'L!P(L)' on 'a' with 'MarkedStrict' to account for+ the strict field. -* That in turn means that, if the usage info supports doing so- (i.e. splitProdDmd_maybe returns Just), we will unpack that argument- -- even though the original demand (e.g. on 'a') was lazy.+* Said 'StrictnessMark' is passed to the recursive invocation of+ 'finaliseBoxity' when deciding whether to unbox 'a'. 'a' was used lazily, but+ since it also says 'MarkedStrict', we'll retain the 'Unboxed' boxity on 'a'. -* What does "bump up the strictness" mean? Just add a head-strict- demand to the strictness! Even for a demand like <L,A> we can- safely turn it into <S,A>; remember case (1) of- Note [Worker/wrapper for Strictness and Absence].+* Worker/wrapper will consult 'wantToUnboxArg' for its unboxing decision. It will+ /not/ look at the strictness bits of the demand, only at Boxity flags. As such,+ it will happily unbox 'a' despite the lazy demand on it. -The net effect is that the w/w transformation is more aggressive about-unpacking the strict arguments of a data constructor, when that-eagerness is supported by the usage info.+The net effect is that boxity analysis and the w/w transformation are more+aggressive about unboxing the strict arguments of a data constructor than when+looking at strictness info exclusively. It is very much like (Nested) CPR, which+needs its nested fields to be evaluated in order for it to unbox nestedly. There is the usual danger of reboxing, which as usual we ignore. But if X is monomorphic, and has an UNPACK pragma, then this optimisation is even more important. We don't want the wrapper to rebox an unboxed argument, and pass an Int to $wfoo! -This works in nested situations like+This works in nested situations like T10482 data family Bar a data instance Bar (a, b) = BarPair !(Bar a) !(Bar b)@@ -861,6 +816,68 @@ that we get the strict demand signature we wanted even if we can't float the case on `x` up through the case on `burble`. +Note [No nested Unboxed inside Boxed in demand signature]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+```+f p@(x,y)+ | even (x+y) = []+ | otherwise = [p]+```+Demand analysis will infer that the function body puts a demand of `1P(1!L,1!L)`+on 'p', e.g., Boxed on the outside but Unboxed on the inside. But worker/wrapper+can't unbox the pair components without unboxing the pair! So we better say+`1P(1L,1L)` in the demand signature in order not to spread wrong Boxity info.+That happens in 'finaliseBoxity'.++Note [No lazy, Unboxed demands in demand signature]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider T19407:++ data Huge = Huge Bool () ... () -- think: DynFlags+ data T = T { h :: Huge, n :: Int }+ f t@(T h _) = g h t+ g (H b _ ... _) t = if b then 1 else n t++The body of `g` puts (approx.) demand `L!P(A,1)` on `t`. But we better+not put that demand in `g`'s demand signature, because worker/wrapper will not+in general unbox a lazy-and-unboxed demand like `L!P(..)`.+(The exception are known-to-be-evaluated arguments like strict fields,+see Note [Unboxing evaluated arguments].)++The program above is an example where spreading misinformed boxity through the+signature is particularly egregious. If we give `g` that signature, then `f`+puts demand `S!P(1!P(1L,A,..),ML)` on `t`. Now we will unbox `t` in `f` it and+we get++ f (T (H b _ ... _) n) = $wf b n+ $wf b n = $wg b (T (H b x ... x) n)+ $wg = ...++Massive reboxing in `$wf`! Solution: Trim boxity on lazy demands in+'finaliseBoxity', modulo Note [Unboxing evaluated arguments].++Note [Finalising boxity for demand signature]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The worker/wrapper pass must strictly adhere to the boxity decisions encoded+in the demand signature, because that is the information that demand analysis+propagates throughout the program. Failing to implement the strategy laid out+in the signature can result in reboxing in unexpected places. Hence, we must+completely anticipate unboxing decisions during demand analysis and reflect+these decicions in demand annotations. That is the job of 'finaliseBoxity',+which is defined here and called from demand analysis.++Here is a list of different Notes it has to take care of:++ * Note [No lazy, Unboxed demands in demand signature] such as `L!P(L)` in+ general, but still allow Note [Unboxing evaluated arguments]+ * Note [No nested Unboxed inside Boxed in demand signature] such as `1P(1!L)`+ * Implement fixes for corner cases Note [Do not unbox class dictionaries]+ and Note [mkWWstr and unsafeCoerce]++Then, in worker/wrapper blindly trusts the boxity info in the demand signature+and will not look at strictness info *at all*, in 'wantToUnboxArg'.+ Note [non-algebraic or open body type warning] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are a few cases where the W/W transformation is told that something@@ -892,7 +909,6 @@ -} mkWWstr :: WwOpts- -> ArgOfInlineableFun -- See Note [Do not unpack class dictionaries] -> [Var] -- Wrapper args; have their demand info on them -- *Includes type variables* -> UniqSM (Bool, -- Is this useful@@ -903,10 +919,10 @@ [CoreExpr]) -- Reboxed args for the call to the -- original RHS. Corresponds one-to-one -- with the wrapper arg vars-mkWWstr opts inlineable_flag args+mkWWstr opts args = go args where- go_one arg = mkWWstr_one opts inlineable_flag arg+ go_one arg = mkWWstr_one opts arg go [] = return (False, [], nop_fn, []) go (arg : args) = do { (useful1, args1, wrap_fn1, wrap_arg) <- go_one arg@@ -923,12 +939,9 @@ -- * wrap_arg assumes work_args are in scope, and builds a ConApp that -- reconstructs the RHS of wrap_var that we pass to the original RHS -- See Note [Worker/wrapper for Strictness and Absence]-mkWWstr_one :: WwOpts- -> ArgOfInlineableFun -- See Note [Do not unpack class dictionaries]- -> Var- -> UniqSM (Bool, [Var], CoreExpr -> CoreExpr, CoreExpr)-mkWWstr_one opts inlineable_flag arg =- case wantToUnboxArg fam_envs inlineable_flag arg_ty arg_dmd of+mkWWstr_one :: WwOpts -> Var -> UniqSM (Bool, [Var], CoreExpr -> CoreExpr, CoreExpr)+mkWWstr_one opts arg =+ case wantToUnboxArg fam_envs arg_ty arg_dmd of _ | isTyVar arg -> do_nothing DropAbsent@@ -938,7 +951,7 @@ -- (that's what mkAbsentFiller does) -> return (True, [], nop_fn, absent_filler) - Unbox dcpc cs -> unbox_one_arg opts arg cs dcpc+ Unbox dcpc ds -> unbox_one_arg opts arg ds dcpc _ -> do_nothing -- Other cases, like StopUnboxing @@ -953,17 +966,17 @@ -> [Demand] -> DataConPatContext -> UniqSM (Bool, [Var], CoreExpr -> CoreExpr, CoreExpr)-unbox_one_arg opts arg_var cs+unbox_one_arg opts arg_var ds DataConPatContext { dcpc_dc = dc, dcpc_tc_args = tc_args , dcpc_co = co } = do { pat_bndrs_uniqs <- getUniquesM ; let ex_name_fss = map getOccFS $ dataConExTyCoVars dc (ex_tvs', arg_ids) = dataConRepFSInstPat (ex_name_fss ++ repeat ww_prefix) pat_bndrs_uniqs (idMult arg_var) dc tc_args- arg_ids' = zipWithEqual "unbox_one_arg" setIdDemandInfo arg_ids cs+ arg_ids' = zipWithEqual "unbox_one_arg" setIdDemandInfo arg_ids ds unbox_fn = mkUnpackCase (Var arg_var) co (idMult arg_var) dc (ex_tvs' ++ arg_ids')- ; (_, worker_args, wrap_fn, wrap_args) <- mkWWstr opts NotArgOfInlineableFun (ex_tvs' ++ arg_ids')+ ; (_, worker_args, wrap_fn, wrap_args) <- mkWWstr opts (ex_tvs' ++ arg_ids') ; let wrap_arg = mkConApp dc (map Type tc_args ++ wrap_args) `mkCast` mkSymCo co ; return (True, worker_args, unbox_fn . wrap_fn, wrap_arg) } -- Don't pass the arg, rebox instead@@ -1003,48 +1016,49 @@ -- will have different lengths and hence different costs for -- the inliner leading to different inlining. -- See also Note [Unique Determinism] in GHC.Types.Unique- file_msg = case wo_output_file opts of- Nothing -> empty- Just f -> text "In output file " <+> quotes (text f)+ file_msg = text "In module" <+> quotes (ppr $ wo_module opts) {- Note [Worker/wrapper for Strictness and Absence] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-The worker/wrapper transformation, mkWWstr_one, takes into account-several possibilities to decide if the function is worthy for-splitting:+The worker/wrapper transformation, mkWWstr_one, takes concrete action+based on the 'UnboxingDescision' returned by 'wantToUnboxArg'.+The latter takes into account several possibilities to decide if the+function is worthy for splitting: 1. If an argument is absent, it would be silly to pass it to- the worker. Hence the isAbsDmd case. This case must come- first because a demand like <S,A> or <B,A> is possible.- E.g. <B,A> comes from a function like+ the worker. Hence the DropAbsent case. This case must come+ first because the bottom demand B is also strict.+ E.g. B comes from a function like f x = error "urk"- and <S,A> can come from Note [Add demands for strict constructors]+ and the absent demand A can come from Note [Unboxing evaluated arguments] -2. If the argument is evaluated strictly, and we can split the- product demand (splitProdDmd_maybe), then unbox it and w/w its- pieces. For example+2. If the argument is evaluated strictly (or known to be eval'd),+ we can take a view into the product demand ('viewProd'). In accordance+ with Note [Boxity analysis], 'wantToUnboxArg' will say 'Unbox'.+ 'mkWWstr_one' then follows suit it and recurses into the fields of the+ product demand. For example - f :: (Int, Int) -> Int- f p = (case p of (a,b) -> a) + 1- is split to- f :: (Int, Int) -> Int- f p = case p of (a,b) -> $wf a+ f :: (Int, Int) -> Int+ f p = (case p of (a,b) -> a) + 1+ is split to+ f :: (Int, Int) -> Int+ f p = case p of (a,b) -> $wf a - $wf :: Int -> Int- $wf a = a + 1+ $wf :: Int -> Int+ $wf a = a + 1 - and- g :: Bool -> (Int, Int) -> Int- g c p = case p of (a,b) ->- if c then a else b- is split to- g c p = case p of (a,b) -> $gw c a b- $gw c a b = if c then a else b+ and+ g :: Bool -> (Int, Int) -> Int+ g c p = case p of (a,b) ->+ if c then a else b+ is split to+ g c p = case p of (a,b) -> $gw c a b+ $gw c a b = if c then a else b -2a But do /not/ split if the components are not used; that is, the- usage is just 'Used' rather than 'UProd'. In this case- splitProdDmd_maybe returns Nothing. Otherwise we risk decomposing- a massive tuple which is barely used. Example:+2a But do /not/ split if Boxity Analysis said "Boxed".+ In this case, 'wantToUnboxArg' returns 'StopUnboxing'.+ Otherwise we risk decomposing and reboxing a massive+ tuple which is barely used. Example: f :: ((Int,Int) -> String) -> (Int,Int) -> a f g pr = error (g pr)@@ -1055,10 +1069,11 @@ Imagine that it had millions of fields. This actually happened in GHC itself where the tuple was DynFlags -3. A plain 'seqDmd', which is head-strict with usage UHead, can't- be split by splitProdDmd_maybe. But we want it to behave just- like U(AAAA) for suitable number of absent demands. So we have- a special case for it, with arity coming from the data constructor.+3. In all other cases (e.g., lazy, used demand and not eval'd),+ 'finaliseBoxity' will have cleared the Boxity flag to 'Boxed'+ (see Note [Finalising boxity for demand signature]) and+ 'wantToUnboxArg' returns 'StopUnboxing' so that 'mkWWstr_one'+ stops unboxing. Note [Worker/wrapper for bottoming functions] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@@ -1162,7 +1177,7 @@ Ideally, we'd just look at the 'StrictnessMark' of the DataCon's field, but it's quite nasty to thread the marks though 'mkWWstr' and 'mkWWstr_one'. So we rather look out for a necessary condition for strict fields:- Note [Add demands for strict constructors] makes it so that the demand on+ Note [Unboxing evaluated arguments] makes it so that the demand on 'zs' is absent and /strict/: It will get cardinality 'C_10', the empty interval, rather than 'C_00'. Hence the 'isStrictDmd' check: It guarantees we never fill in an error-thunk for an absent strict field.@@ -1333,6 +1348,8 @@ go_arg_ty :: IntWithInf -> RecTcChecker -> Type -> IsRecDataConResult go_arg_ty fuel rec_tc ty+ --- | pprTrace "arg_ty" (ppr ty) False = undefined+ | Just (_, _arg_ty, _res_ty) <- splitFunTy_maybe ty -- = go_arg_ty fuel rec_tc _arg_ty <||> go_arg_ty fuel rec_tc _res_ty -- Plausible, but unnecessary for CPR.@@ -1382,7 +1399,7 @@ -- we expanded this TyCon once already, no need to test it multiple times Just rec_tc'- | Just (_tvs, rhs, _co) <- unwrapNewTyConEtad_maybe tc+ | Just (_tvs, rhs, _co) <- unwrapNewTyCon_maybe tc -- See Note [Detecting recursive data constructors], points (2) and (3) -> go_arg_ty fuel rec_tc' rhs @@ -1392,6 +1409,56 @@ | let dcs = expectJust "isRecDataCon:go_tc_app" $ tyConDataCons_maybe tc -> combineIRDCRs (map (\dc -> go_dc (subWithInf fuel 1) rec_tc' dc) dcs) -- See Note [Detecting recursive data constructors], point (4)++-- | A specialised Bool for an argument to 'finaliseBoxity'.+-- See Note [Do not unbox class dictionaries].+data InsideInlineableFun+ = NotInsideInlineableFun -- ^ Not in an inlineable fun.+ | InsideInlineableFun -- ^ We are in an inlineable fun, so we won't+ -- unbox dictionary args.+ deriving Eq++-- | This function makes sure that the demand only says 'Unboxed' where+-- worker/wrapper should actually unbox and trims any boxity beyond that.+-- Called for every demand annotation during DmdAnal.+--+-- > data T a = T !a+-- > f :: (T (Int,Int), Int) -> ()+-- > f p = ... -- demand on p: 1!P(L!P(L!P(L), L!P(L)), L!P(L))+--+-- 'finaliseBoxity' will trim the demand on 'p' to 1!P(L!P(LP(L), LP(L)), LP(L)).+-- This is done when annotating lambdas and thunk bindings.+-- See Note [Finalising boxity for demand signature]+finaliseBoxity+ :: FamInstEnvs+ -> InsideInlineableFun -- ^ See the haddocks on 'InsideInlineableFun'+ -> Type -- ^ Type of the argument+ -> Demand -- ^ How the arg was used+ -> Demand+finaliseBoxity env in_inl_fun ty dmd = go NotMarkedStrict ty dmd+ where+ go mark ty dmd@(n :* _) =+ case wantToUnboxArg env ty dmd of+ DropAbsent -> dmd+ Unbox DataConPatContext{dcpc_dc=dc, dcpc_tc_args=tc_args} ds+ -- See Note [No lazy, Unboxed demands in demand signature]+ -- See Note [Unboxing evaluated arguments]+ | isStrict n || isMarkedStrict mark+ -- See Note [Do not unbox class dictionaries]+ , in_inl_fun == NotInsideInlineableFun || not (isClassPred ty)+ -- See Note [mkWWstr and unsafeCoerce]+ , ds `lengthIs` dataConRepArity dc+ , let arg_tys = dubiousDataConInstArgTys dc tc_args+ -> -- pprTrace "finaliseBoxity:Unbox" (ppr ty $$ ppr dmd $$ ppr ds) $+ n :* (mkProd Unboxed $! zip_go_with_marks dc arg_tys ds)+ -- See Note [No nested Unboxed inside Boxed in demand signature]+ _ -> trimBoxity dmd++ -- See Note [Unboxing evaluated arguments]+ zip_go_with_marks dc arg_tys ds = case dataConWrapId_maybe dc of+ Nothing -> strictZipWith (go NotMarkedStrict) arg_tys ds+ -- Shortcut when DataCon worker=wrapper+ Just _ -> strictZipWith3 go (dataConRepStrictness dc) arg_tys ds {- ************************************************************************
compiler/GHC/Driver/Backpack.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE NondecreasingIndentation #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-} -- | This is the driver for the 'ghc --backpack' mode, which@@ -38,6 +39,8 @@ import GHC.Parser.Lexer import GHC.Parser.Annotation +import GHC.Rename.Names+ import GHC hiding (Failed, Succeeded) import GHC.Tc.Utils.Monad import GHC.Iface.Recomp@@ -45,7 +48,6 @@ import GHC.Types.SrcLoc import GHC.Types.SourceError-import GHC.Types.SourceText import GHC.Types.SourceFile import GHC.Types.Unique.FM import GHC.Types.Unique.DFM@@ -91,8 +93,6 @@ -- | Entry point to compile a Backpack file. doBackpack :: [FilePath] -> Ghc () doBackpack [src_filename] = do- logger <- getLogger- -- Apply options from file to dflags dflags0 <- getDynFlags let dflags1 = dflags0@@ -100,6 +100,9 @@ src_opts <- liftIO $ getOptionsFromFile parser_opts1 src_filename (dflags, unhandled_flags, warns) <- liftIO $ parseDynamicFilePragma dflags1 src_opts modifySession (hscSetFlags dflags)+ logger <- getLogger -- Get the logger after having set the session flags,+ -- so that logger options are correctly set.+ -- Not doing so caused #20396. -- Cribbed from: preprocessFile / GHC.Driver.Pipeline liftIO $ checkProcessArgsResult unhandled_flags liftIO $ handleFlagWarnings logger (initDiagOpts dflags) warns@@ -121,14 +124,14 @@ innerBkpM $ do let (cid, insts) = computeUnitId lunit if null insts- then if cid == Indefinite (UnitId (fsLit "main"))+ then if cid == UnitId (fsLit "main") then compileExe lunit else compileUnit cid [] else typecheckUnit cid insts doBackpack _ = throwGhcException (CmdLineError "--backpack can only process a single file") -computeUnitId :: LHsUnit HsComponentId -> (IndefUnitId, [(ModuleName, Module)])+computeUnitId :: LHsUnit HsComponentId -> (UnitId, [(ModuleName, Module)]) computeUnitId (L _ unit) = (cid, [ (r, mkHoleModule r) | r <- reqs ]) where cid = hsComponentId (unLoc (hsunitName unit))@@ -154,7 +157,7 @@ -- | Create a temporary Session to do some sort of type checking or -- compilation.-withBkpSession :: IndefUnitId+withBkpSession :: UnitId -> [(ModuleName, Module)] -> [(Unit, ModRenaming)] -> SessionType -- what kind of session are we doing@@ -162,7 +165,7 @@ -> BkpM a withBkpSession cid insts deps session_type do_this = do dflags <- getDynFlags- let cid_fs = unitFS (indefUnit cid)+ let cid_fs = unitFS cid is_primary = False uid_str = unpackFS (mkInstantiatedUnitHash cid insts) cid_str = unpackFS cid_fs@@ -192,7 +195,7 @@ -- if we don't have any instantiation, don't -- fill `homeUnitInstanceOfId` as it makes no -- sense (we're not instantiating anything)- , homeUnitInstanceOf_ = if null insts then Nothing else Just (indefUnit cid)+ , homeUnitInstanceOf_ = if null insts then Nothing else Just cid , homeUnitId_ = case session_type of TcSession -> newUnitId cid Nothing -- No hash passed if no instances@@ -244,21 +247,21 @@ withBkpExeSession :: [(Unit, ModRenaming)] -> BkpM a -> BkpM a withBkpExeSession deps do_this =- withBkpSession (Indefinite (UnitId (fsLit "main"))) [] deps ExeSession do_this+ withBkpSession (UnitId (fsLit "main")) [] deps ExeSession do_this -getSource :: IndefUnitId -> BkpM (LHsUnit HsComponentId)+getSource :: UnitId -> BkpM (LHsUnit HsComponentId) getSource cid = do bkp_env <- getBkpEnv case Map.lookup cid (bkp_table bkp_env) of Nothing -> pprPanic "missing needed dependency" (ppr cid) Just lunit -> return lunit -typecheckUnit :: IndefUnitId -> [(ModuleName, Module)] -> BkpM ()+typecheckUnit :: UnitId -> [(ModuleName, Module)] -> BkpM () typecheckUnit cid insts = do lunit <- getSource cid buildUnit TcSession cid insts lunit -compileUnit :: IndefUnitId -> [(ModuleName, Module)] -> BkpM ()+compileUnit :: UnitId -> [(ModuleName, Module)] -> BkpM () compileUnit cid insts = do -- Let everyone know we're building this unit msgUnitId (mkVirtUnit cid insts)@@ -286,7 +289,7 @@ convRn (L _ (Renaming (L _ from) (Just (L _ to)))) = (from, to) get_dep _ = [] -buildUnit :: SessionType -> IndefUnitId -> [(ModuleName, Module)] -> LHsUnit HsComponentId -> BkpM ()+buildUnit :: SessionType -> UnitId -> [(ModuleName, Module)] -> LHsUnit HsComponentId -> BkpM () buildUnit session cid insts lunit = do -- NB: include signature dependencies ONLY when typechecking. -- If we're compiling, it's not necessary to recursively@@ -322,7 +325,7 @@ mod_graph <- hsunitModuleGraph (unLoc lunit) msg <- mkBackpackMsg- ok <- load' LoadAllTargets (Just msg) mod_graph+ (ok, _) <- load' [] LoadAllTargets (Just msg) mod_graph when (failed ok) (liftIO $ exitWith (ExitFailure 1)) let hi_dir = expectJust (panic "hiDir Backpack") $ hiDir dflags@@ -341,7 +344,7 @@ obj_files = concatMap getOfiles linkables state = hsc_units hsc_env - let compat_fs = unitIdFS (indefUnit cid)+ let compat_fs = unitIdFS cid compat_pn = PackageName compat_fs unit_id = homeUnitId (hsc_home_unit hsc_env) @@ -411,7 +414,7 @@ withBkpExeSession deps_w_rns $ do mod_graph <- hsunitModuleGraph (unLoc lunit) msg <- mkBackpackMsg- ok <- load' LoadAllTargets (Just msg) mod_graph+ (ok, _) <- load' [] LoadAllTargets (Just msg) mod_graph when (failed ok) (liftIO $ exitWith (ExitFailure 1)) -- | Register a new virtual unit database containing a single unit@@ -474,7 +477,7 @@ -- | The filename of the bkp file we're compiling bkp_filename :: FilePath, -- | Table of source units which we know how to compile- bkp_table :: Map IndefUnitId (LHsUnit HsComponentId),+ bkp_table :: Map UnitId (LHsUnit HsComponentId), -- | When a package we are compiling includes another package -- which has not been compiled, we bump the level and compile -- that.@@ -630,7 +633,7 @@ -- to use this for anything unitDefines :: LHsUnit PackageName -> (PackageName, HsComponentId) unitDefines (L _ HsUnit{ hsunitName = L _ pn@(PackageName fs) })- = (pn, HsComponentId pn (Indefinite (UnitId fs)))+ = (pn, HsComponentId pn (UnitId fs)) bkpPackageNameMap :: [LHsUnit PackageName] -> PackageNameMap HsComponentId bkpPackageNameMap units = listToUFM (map unitDefines units)@@ -756,8 +759,8 @@ let fopts = initFinderOpts dflags let PackageName pn_fs = pn- location <- liftIO $ mkHomeModLocation2 fopts mod_name- (unpackFS pn_fs </> moduleNameSlashes mod_name) "hsig"+ let location = mkHomeModLocation2 fopts mod_name+ (unpackFS pn_fs </> moduleNameSlashes mod_name) "hsig" env <- getBkpEnv src_hash <- liftIO $ getFileHash (bkp_filename env)@@ -780,13 +783,13 @@ ms_iface_date = hi_timestamp, ms_hie_date = hie_timestamp, ms_srcimps = [],- ms_textual_imps = extra_sig_imports,+ ms_textual_imps = ((,) NoPkgQual . noLoc) <$> extra_sig_imports, ms_ghc_prim_import = False, ms_parsed_mod = Just (HsParsedModule { hpm_module = L loc (HsModule { hsmodAnn = noAnn, hsmodLayout = NoLayoutInfo,- hsmodName = Just (L loc mod_name),+ hsmodName = Just (L (noAnnSrcSpan loc) mod_name), hsmodExports = Nothing, hsmodImports = [], hsmodDecls = [],@@ -847,7 +850,7 @@ -- To add insult to injury, we don't even actually use -- these filenames to figure out where the hi files go. -- A travesty!- location0 <- liftIO $ mkHomeModLocation2 fopts modname+ let location0 = mkHomeModLocation2 fopts modname (unpackFS unit_fs </> moduleNameSlashes modname) (case hsc_src of@@ -873,8 +876,10 @@ implicit_prelude = xopt LangExt.ImplicitPrelude dflags implicit_imports = mkPrelImports modname loc implicit_prelude imps- convImport (L _ i) = (fmap sl_fs (ideclPkgQual i), ideclName i) + rn_pkg_qual = renameRawPkgQual (hsc_unit_env hsc_env)+ convImport (L _ i) = (rn_pkg_qual (ideclPkgQual i), reLoc $ ideclName i)+ extra_sig_imports <- liftIO $ findExtraSigImports hsc_env hsc_src modname let normal_imports = map convImport (implicit_imports ++ ordinary_imps)@@ -902,8 +907,8 @@ -- We have to do something special here: -- due to merging, requirements may end up with -- extra imports- ++ extra_sig_imports- ++ ((,) Nothing . noLoc <$> implicit_sigs),+ ++ ((,) NoPkgQual . noLoc <$> extra_sig_imports)+ ++ ((,) NoPkgQual . noLoc <$> implicit_sigs), -- This is our hack to get the parse tree to the right spot ms_parsed_mod = Just (HsParsedModule { hpm_module = hsmod,@@ -923,7 +928,7 @@ -- | Create a new, externally provided hashed unit id from -- a hash.-newUnitId :: IndefUnitId -> Maybe FastString -> UnitId+newUnitId :: UnitId -> Maybe FastString -> UnitId newUnitId uid mhash = case mhash of- Nothing -> indefUnit uid- Just hash -> UnitId (unitIdFS (indefUnit uid) `appendFS` mkFastString "+" `appendFS` hash)+ Nothing -> uid+ Just hash -> UnitId (unitIdFS uid `appendFS` mkFastString "+" `appendFS` hash)
compiler/GHC/Driver/Config/CmmToAsm.hs view
@@ -11,6 +11,7 @@ import GHC.Unit.Types (Module) import GHC.CmmToAsm.Config import GHC.Utils.Outputable+import GHC.CmmToAsm.BlockLayout -- | Initialize the native code generator configuration from the DynFlags initNCGConfig :: DynFlags -> Module -> NCGConfig@@ -67,4 +68,8 @@ , ncgCmmStaticPred = gopt Opt_CmmStaticPred dflags , ncgEnableShortcutting = gopt Opt_AsmShortcutting dflags , ncgComputeUnwinding = debugLevel dflags > 0+ , ncgEnableDeadCodeElimination = not (gopt Opt_InfoTableMap dflags)+ -- Disable when -finfo-table-map is on (#20428)+ && backendMaintainsCfg (targetPlatform dflags)+ -- Enable if the platform maintains the CFG }
+ compiler/GHC/Driver/Config/Finder.hs view
@@ -0,0 +1,29 @@+module GHC.Driver.Config.Finder (+ FinderOpts(..),+ initFinderOpts+ ) where++import GHC.Prelude++import GHC.Driver.Session+import GHC.Unit.Finder.Types+++-- | Create a new 'FinderOpts' from DynFlags.+initFinderOpts :: DynFlags -> FinderOpts+initFinderOpts flags = FinderOpts+ { finder_importPaths = importPaths flags+ , finder_lookupHomeInterfaces = isOneShot (ghcMode flags)+ , finder_bypassHiFileCheck = MkDepend == (ghcMode flags)+ , finder_ways = ways flags+ , finder_enableSuggestions = gopt Opt_HelpfulErrors flags+ , finder_hieDir = hieDir flags+ , finder_hieSuf = hieSuf flags+ , finder_hiDir = hiDir flags+ , finder_hiSuf = hiSuf_ flags+ , finder_dynHiSuf = dynHiSuf_ flags+ , finder_objectDir = objectDir flags+ , finder_objectSuf = objectSuf_ flags+ , finder_dynObjectSuf = dynObjectSuf_ flags+ , finder_stubDir = stubDir flags+ }
compiler/GHC/Driver/Main.hs view
@@ -239,6 +239,7 @@ import GHC.Driver.Env.KnotVars import GHC.Types.Name.Set (NonCaffySet) import GHC.Driver.GenerateCgIPEStub (generateCgIPEStub)+import Data.List.NonEmpty (NonEmpty ((:|))) {- **********************************************************************@@ -411,6 +412,17 @@ Nothing -> liftIO $ hGetStringBuffer src_filename let loc = mkRealSrcLoc (mkFastString src_filename) 1 1++ let diag_opts = initDiagOpts dflags+ when (wopt Opt_WarnUnicodeBidirectionalFormatCharacters dflags) $ do+ case checkBidirectionFormatChars (PsLoc loc (BufPos 0)) buf of+ Nothing -> pure ()+ Just chars@((eloc,chr,_) :| _) ->+ let span = mkSrcSpanPs $ mkPsSpan eloc (advancePsLoc eloc chr)+ in logDiagnostics $ singleMessage $+ mkPlainMsgEnvelope diag_opts span $+ GhcPsMessage $ PsWarnBidirectionalFormatChars chars+ let parseMod | HsigFile == ms_hsc_src mod_summary = parseSignature | otherwise = parseModule@@ -469,9 +481,34 @@ hsc_env <- getHscEnv withPlugins hsc_env applyPluginAction res +checkBidirectionFormatChars :: PsLoc -> StringBuffer -> Maybe (NonEmpty (PsLoc, Char, String))+checkBidirectionFormatChars start_loc sb+ | containsBidirectionalFormatChar sb = Just $ go start_loc sb+ | otherwise = Nothing+ where+ go :: PsLoc -> StringBuffer -> NonEmpty (PsLoc, Char, String)+ go loc sb+ | atEnd sb = panic "checkBidirectionFormatChars: no char found"+ | otherwise = case nextChar sb of+ (chr, sb)+ | Just desc <- lookup chr bidirectionalFormatChars ->+ (loc, chr, desc) :| go1 (advancePsLoc loc chr) sb+ | otherwise -> go (advancePsLoc loc chr) sb + go1 :: PsLoc -> StringBuffer -> [(PsLoc, Char, String)]+ go1 loc sb+ | atEnd sb = []+ | otherwise = case nextChar sb of+ (chr, sb)+ | Just desc <- lookup chr bidirectionalFormatChars ->+ (loc, chr, desc) : go1 (advancePsLoc loc chr) sb+ | otherwise -> go1 (advancePsLoc loc chr) sb++ -- ----------------------------------------------------------------------------- -- | If the renamed source has been kept, extract it. Dump it if requested.++ extract_renamed_stuff :: ModSummary -> TcGblEnv -> Hsc RenamedStuff extract_renamed_stuff mod_summary tc_result = do let rn_info = getRenamedStuff tc_result@@ -733,8 +770,8 @@ -- or not. checkObjects :: DynFlags -> Maybe Linkable -> ModSummary -> IO (RecompileRequired, Maybe Linkable) checkObjects dflags mb_old_linkable summary = do- dt_state <- dynamicTooState dflags let+ dt_enabled = gopt Opt_BuildDynamicToo dflags this_mod = ms_mod summary mb_obj_date = ms_obj_date summary mb_dyn_obj_date = ms_dyn_obj_date summary@@ -743,12 +780,12 @@ -- dynamic-too *also* produces the dyn_o_file, so have to check -- that's there, and if it's not, regenerate both .o and -- .dyn_o- checkDynamicObj k = case dt_state of- DT_OK -> case (>=) <$> mb_dyn_obj_date <*> mb_if_date of+ checkDynamicObj k = if dt_enabled+ then case (>=) <$> mb_dyn_obj_date <*> mb_if_date of Just True -> k _ -> return (RecompBecause MissingDynObjectFile, Nothing) -- Not in dynamic-too mode- _ -> k+ else k checkDynamicObj $ case (,) <$> mb_obj_date <*> mb_if_date of@@ -962,18 +999,8 @@ Interpreter -> False _ -> True - -- mod_location only contains the base name, so we rebuild the- -- correct file extension from the dynflags.- baseName = ml_hi_file mod_location- buildIfName suffix is_dynamic- | Just name <- (if is_dynamic then dynOutputHi else outputHi) dflags- = name- | otherwise- = let with_hi = replaceExtension baseName suffix- in addBootSuffix_maybe (mi_boot iface) with_hi- write_iface dflags' iface =- let !iface_name = buildIfName (hiSuf dflags') (dynamicNow dflags')+ let !iface_name = if dynamicNow dflags' then ml_dyn_hi_file mod_location else ml_hi_file mod_location profile = targetProfile dflags' in {-# SCC "writeIface" #-}@@ -982,7 +1009,7 @@ (const ()) (writeIface logger profile iface_name iface) - when (write_interface || force_write_interface) $ do+ if (write_interface || force_write_interface) then do -- FIXME: with -dynamic-too, "no_change" is only meaningful for the -- non-dynamic interface, not for the dynamic one. We should have another@@ -999,7 +1026,7 @@ -- let no_change = old_iface == Just (mi_iface_hash (mi_final_exts iface)) - dt <- dynamicTooState dflags+ let dt = dynamicTooState dflags when (logHasDumpFlag logger Opt_D_dump_if_trace) $ putMsg logger $ hang (text "Writing interface(s):") 2 $ vcat@@ -1013,7 +1040,6 @@ write_iface dflags iface case dt of DT_Dont -> return ()- DT_Failed -> return () DT_Dyn -> panic "Unexpected DT_Dyn state when writing simple interface" DT_OK -> write_iface (setDynamicNow dflags) iface else case dt of@@ -1021,7 +1047,6 @@ DT_OK | not no_change -> write_iface dflags iface -- FIXME: see no_change' comment above DT_Dyn -> write_iface dflags iface- DT_Failed | not (dynamicNow dflags) -> write_iface dflags iface _ -> return () when (gopt Opt_WriteHie dflags) $ do@@ -1039,6 +1064,9 @@ let hie_file = ml_hie_file mod_location whenM (doesFileExist hie_file) $ GHC.SysTools.touch logger dflags "Touching hie file" hie_file+ else+ -- See Note [Strictness in ModIface]+ forceModIface iface -------------------------------------------------------------- -- NoRecomp handlers@@ -1714,6 +1742,8 @@ no_loc = ModLocation{ ml_hs_file = Just filename, ml_hi_file = panic "hscCompileCmmFile: no hi file", ml_obj_file = panic "hscCompileCmmFile: no obj file",+ ml_dyn_obj_file = panic "hscCompileCmmFile: no dyn obj file",+ ml_dyn_hi_file = panic "hscCompileCmmFile: no dyn obj file", ml_hie_file = panic "hscCompileCmmFile: no hie file"} -------------------- Stuff for new code gen ---------------------@@ -1945,6 +1975,8 @@ let iNTERACTIVELoc = ModLocation{ ml_hs_file = Nothing, ml_hi_file = panic "hsDeclsWithLocation:ml_hi_file", ml_obj_file = panic "hsDeclsWithLocation:ml_obj_file",+ ml_dyn_obj_file = panic "hsDeclsWithLocation:ml_dyn_obj_file",+ ml_dyn_hi_file = panic "hsDeclsWithLocation:ml_dyn_hi_file", ml_hie_file = panic "hsDeclsWithLocation:ml_hie_file" } ds_result <- hscDesugar' iNTERACTIVELoc tc_gblenv @@ -2155,6 +2187,8 @@ ; let iNTERACTIVELoc = ModLocation{ ml_hs_file = Nothing, ml_hi_file = panic "hscCompileCoreExpr':ml_hi_file", ml_obj_file = panic "hscCompileCoreExpr':ml_obj_file",+ ml_dyn_obj_file = panic "hscCompileCoreExpr': ml_obj_file",+ ml_dyn_hi_file = panic "hscCompileCoreExpr': ml_dyn_hi_file", ml_hie_file = panic "hscCompileCoreExpr':ml_hie_file" } ; let ictxt = hsc_IC hsc_env
compiler/GHC/Driver/Make.hs view
@@ -27,7 +27,7 @@ -- ----------------------------------------------------------------------------- module GHC.Driver.Make ( depanal, depanalE, depanalPartial,- load, load', LoadHowMuch(..),+ load, loadWithCache, load', LoadHowMuch(..), instantiationNodes, downsweep,@@ -87,7 +87,7 @@ import GHC.Data.StringBuffer import qualified GHC.LanguageExtensions as LangExt -import GHC.Utils.Exception ( evaluate, throwIO, SomeAsyncException )+import GHC.Utils.Exception ( throwIO, SomeAsyncException ) import GHC.Utils.Outputable import GHC.Utils.Panic import GHC.Utils.Panic.Plain@@ -108,6 +108,7 @@ import GHC.Types.Unique.Set import GHC.Types.Name import GHC.Types.Name.Env+import GHC.Types.PkgQual import GHC.Unit import GHC.Unit.Finder@@ -149,6 +150,7 @@ import Control.Concurrent.STM import Control.Monad.Trans.Maybe import GHC.Runtime.Loader+import GHC.Rename.Names -- -----------------------------------------------------------------------------@@ -346,11 +348,14 @@ -- returns together with the errors an empty ModuleGraph. -- After processing this empty ModuleGraph, the errors of depanalE are thrown. -- All other errors are reported using the 'defaultWarnErrLogger'.----load :: GhcMonad m => LoadHowMuch -> m SuccessFlag-load how_much = do++load :: GhcMonad f => LoadHowMuch -> f SuccessFlag+load how_much = fst <$> loadWithCache [] how_much++loadWithCache :: GhcMonad m => [HomeModInfo] -> LoadHowMuch -> m (SuccessFlag, [HomeModInfo])+loadWithCache cache how_much = do (errs, mod_graph) <- depanalE [] False -- #17459- success <- load' how_much (Just batchMsg) mod_graph+ success <- load' cache how_much (Just batchMsg) mod_graph if isEmptyMessages errs then pure success else throwErrors (fmap GhcDriverMessage errs)@@ -468,7 +473,7 @@ -- hs-boot files which are **not** part of cycles. collapseAcyclic :: [SCC ModuleGraphNode] -> [BuildPlan] collapseAcyclic (AcyclicSCC node : nodes) = SingleModule node : collapseAcyclic nodes- collapseAcyclic (CyclicSCC nodes : _) = [UnresolvedCycle nodes]+ collapseAcyclic (CyclicSCC cy_nodes : nodes) = (UnresolvedCycle cy_nodes) : collapseAcyclic nodes collapseAcyclic [] = [] topSortWithBoot nodes = topSortModules False (select_boot_modules nodes ++ nodes) Nothing@@ -483,13 +488,12 @@ -- | Generalized version of 'load' which also supports a custom -- 'Messager' (for reporting progress) and 'ModuleGraph' (generally -- produced by calling 'depanal'.-load' :: GhcMonad m => LoadHowMuch -> Maybe Messager -> ModuleGraph -> m SuccessFlag-load' how_much mHscMessage mod_graph = do+load' :: GhcMonad m => [HomeModInfo] -> LoadHowMuch -> Maybe Messager -> ModuleGraph -> m (SuccessFlag, [HomeModInfo])+load' cache how_much mHscMessage mod_graph = do modifySession $ \hsc_env -> hsc_env { hsc_mod_graph = mod_graph } guessOutputFile hsc_env <- getSession - let hpt1 = hsc_HPT hsc_env let dflags = hsc_dflags hsc_env let logger = hsc_logger hsc_env let interp = hscInterp hsc_env@@ -519,7 +523,7 @@ | otherwise = do liftIO $ errorMsg logger (text "no such module:" <+> quotes (ppr m))- return Failed+ return (Failed, []) checkHowMuch how_much $ do @@ -545,15 +549,14 @@ let -- prune the HPT so everything is not retained when doing an -- upsweep.- pruned_hpt = pruneHomePackageTable hpt1+ !pruned_cache = pruneCache cache (flattenSCCs (filterToposortToModules mg2_with_srcimps)) - _ <- liftIO $ evaluate pruned_hpt -- before we unload anything, make sure we don't leave an old -- interactive context around pointing to dead bindings. Also,- -- write the pruned HPT to allow the old HPT to be GC'd.- setSession $ discardIC $ hscUpdateHPT (const pruned_hpt) hsc_env+ -- write an empty HPT to allow the old HPT to be GC'd.+ setSession $ discardIC $ hscUpdateHPT (const emptyHomePackageTable) hsc_env -- Unload everything liftIO $ unload interp hsc_env@@ -568,11 +571,13 @@ Just n -> return n setSession $ hscUpdateHPT (const emptyHomePackageTable) hsc_env- (upsweep_ok, hsc_env1) <- withDeferredDiagnostics $- liftIO $ upsweep n_jobs hsc_env mHscMessage pruned_hpt direct_deps build_plan+ hsc_env <- getSession+ (upsweep_ok, hsc_env1, new_cache) <- withDeferredDiagnostics $+ liftIO $ upsweep n_jobs hsc_env mHscMessage (toCache pruned_cache) direct_deps build_plan setSession hsc_env1- case upsweep_ok of+ fmap (, new_cache) $ case upsweep_ok of Failed -> loadFinish upsweep_ok Succeeded+ Succeeded -> do -- Make modsDone be the summaries for each home module now -- available; this should equal the domain of hpt3.@@ -594,7 +599,7 @@ -- called Main, or (b) the user said -no-hs-main, indicating -- that main() is going to come from somewhere else. --- let ofile = outputFile dflags+ let ofile = outputFile_ dflags let no_hs_main = gopt Opt_NoHsMain dflags let main_mod = mainModIs hsc_env@@ -696,11 +701,11 @@ ml_hs_file (ms_location ms) name = fmap dropExtension mainModuleSrcPath - name_exe = do+ !name_exe = do -- we must add the .exe extension unconditionally here, otherwise -- when name has an extension of its own, the .exe extension will -- not be added by GHC.Driver.Pipeline.exeFileName. See #2248- name' <- if platformOS platform == OSMinGW32+ !name' <- if platformOS platform == OSMinGW32 then fmap (<.> "exe") name else name mainModuleSrcPath' <- mainModuleSrcPath@@ -729,19 +734,20 @@ -- space at the end of the upsweep, because the topmost ModDetails of the -- old HPT holds on to the entire type environment from the previous -- compilation.-pruneHomePackageTable :: HomePackageTable+-- Note [GHC Heap Invariants]+pruneCache :: [HomeModInfo] -> [ModSummary]- -> HomePackageTable-pruneHomePackageTable hpt summ- = mapHpt prune hpt+ -> [HomeModInfo]+pruneCache hpt summ+ = strictMap prune hpt where prune hmi = hmi'{ hm_details = emptyModDetails } where modl = moduleName (mi_module (hm_iface hmi))- hmi' | mi_src_hash (hm_iface hmi) /= ms_hs_hash ms+ hmi' | Just ms <- lookupUFM ms_map modl+ , mi_src_hash (hm_iface hmi) /= ms_hs_hash ms = hmi{ hm_linkable = Nothing } | otherwise = hmi- where ms = expectJust "prune" (lookupUFM ms_map modl) ms_map = listToUFM [(ms_mod_name ms, ms) | ms <- summ] @@ -920,11 +926,14 @@ withAbstractSem sem = MC.bracket_ (acquireSem sem) (releaseSem sem) -- | Environment used when compiling a module-data MakeEnv = MakeEnv { hsc_env :: HscEnv -- The basic HscEnv which will be augmented for each module- , old_hpt :: HomePackageTable -- A cache of old interface files- , compile_sem :: AbstractSem- , lqq_var :: TVar LogQueueQueue- , env_messager :: Maybe Messager+data MakeEnv = MakeEnv { hsc_env :: !HscEnv -- The basic HscEnv which will be augmented for each module+ , compile_sem :: !AbstractSem+ -- Modify the environment for module k, with the supplied logger modification function.+ -- For -j1, this wrapper doesn't do anything+ -- For -jn, the wrapper initialised a log queue and then modifies the logger to pipe its output+ -- into the log queue.+ , withLogger :: forall a . Int -> ((Logger -> Logger) -> RunMakeM a) -> RunMakeM a+ , env_messager :: !(Maybe Messager) } type RunMakeM a = ReaderT MakeEnv (MaybeT IO) a@@ -933,12 +942,13 @@ -- get its direct dependencies from. This might not be the corresponding build action -- if the module participates in a loop. This step also labels each node with a number for the output. -- See Note [Upsweep] for a high-level description.-interpretBuildPlan :: (NodeKey -> [NodeKey])+interpretBuildPlan :: (M.Map ModuleNameWithIsBoot HomeModInfo)+ -> (NodeKey -> [NodeKey]) -> [BuildPlan] -> IO ( Maybe [ModuleGraphNode] -- Is there an unresolved cycle , [MakeAction] -- Actions we need to run in order to build everything , IO [Maybe (Maybe HomeModInfo)]) -- An action to query to get all the built modules at the end.-interpretBuildPlan deps_map plan = do+interpretBuildPlan old_hpt deps_map plan = do hpt_var <- newMVar emptyHomePackageTable ((mcycle, plans), build_map) <- runStateT (buildLoop plan) (BuildLoopState M.empty 1 hpt_var) return (mcycle, plans, collect_results (buildDep build_map))@@ -986,10 +996,11 @@ case mod of InstantiationNode iu -> const Nothing <$> executeInstantiationNode mod_idx n_mods (wait_deps_hpt hpt_var build_deps) iu ModuleNode ms -> do- hmi <- executeCompileNode mod_idx n_mods (wait_deps_hpt hpt_var build_deps) knot_var (emsModSummary ms)+ let !old_hmi = M.lookup (msKey $ emsModSummary ms) old_hpt+ hmi <- executeCompileNode mod_idx n_mods old_hmi (wait_deps_hpt hpt_var build_deps) knot_var (emsModSummary ms) -- This global MVar is incrementally modified in order to avoid having to -- recreate the HPT before compiling each module which leads to a quadratic amount of work.- liftIO $ modifyMVar_ hpt_var (return . addHomeModInfoToHpt hmi)+ liftIO $ modifyMVar_ hpt_var (\hpt -> return $! addHomeModInfoToHpt hmi hpt) return (Just hmi) res_var <- liftIO newEmptyMVar@@ -1008,8 +1019,8 @@ hpt_var <- gets hpt_var res_var <- liftIO newEmptyMVar let loop_action = do- hmis <- executeTypecheckLoop (readMVar hpt_var) (wait_deps wait_modules)- liftIO $ modifyMVar_ hpt_var (\hpt -> return $ foldl' (flip addHomeModInfoToHpt) hpt hmis)+ !hmis <- executeTypecheckLoop (readMVar hpt_var) (wait_deps wait_modules)+ liftIO $ modifyMVar_ hpt_var (\hpt -> return $! foldl' (flip addHomeModInfoToHpt) hpt hmis) return hmis @@ -1029,13 +1040,13 @@ :: Int -- ^ The number of workers we wish to run in parallel -> HscEnv -- ^ The base HscEnv, which is augmented for each module -> Maybe Messager- -> HomePackageTable+ -> M.Map ModuleNameWithIsBoot HomeModInfo -> (NodeKey -> [NodeKey]) -- A function which computes the direct dependencies of a NodeKey -> [BuildPlan]- -> IO (SuccessFlag, HscEnv)+ -> IO (SuccessFlag, HscEnv, [HomeModInfo]) upsweep n_jobs hsc_env mHscMessage old_hpt direct_deps build_plan = do- (cycle, pipelines, collect_result) <- interpretBuildPlan direct_deps build_plan- runPipelines n_jobs hsc_env old_hpt mHscMessage pipelines+ (cycle, pipelines, collect_result) <- interpretBuildPlan old_hpt direct_deps build_plan+ runPipelines n_jobs hsc_env mHscMessage pipelines res <- collect_result let completed = [m | Just (Just m) <- res]@@ -1047,11 +1058,14 @@ Just mss -> do let logger = hsc_logger hsc_env liftIO $ fatalErrorMsg logger (cyclicModuleErr mss)- return (Failed, hsc_env)+ return (Failed, hsc_env, completed) Nothing -> do let success_flag = successIf (all isJust res)- return (success_flag, hsc_env')+ return (success_flag, hsc_env', completed) +toCache :: [HomeModInfo] -> M.Map ModuleNameWithIsBoot HomeModInfo+toCache hmis = M.fromList ([(mi_mnwib $ hm_iface hmi, hmi) | hmi <- hmis])+ upsweep_inst :: HscEnv -> Maybe Messager -> Int -- index of module@@ -1069,34 +1083,14 @@ -- successful. If no compilation happened, return the old Linkable. upsweep_mod :: HscEnv -> Maybe Messager- -> HomePackageTable+ -> Maybe HomeModInfo -> ModSummary -> Int -- index of module -> Int -- total number of modules -> IO HomeModInfo-upsweep_mod hsc_env mHscMessage old_hpt summary mod_index nmods = do- let old_hmi = lookupHpt old_hpt (ms_mod_name summary)-- -- The old interface is ok if- -- a) we're compiling a source file, and the old HPT- -- entry is for a source file- -- b) we're compiling a hs-boot file- -- Case (b) allows an hs-boot file to get the interface of its- -- real source file on the second iteration of the compilation- -- manager, but that does no harm. Otherwise the hs-boot file- -- will always be recompiled-- mb_old_iface- = case old_hmi of- Nothing -> Nothing- Just hm_info | isBootSummary summary == IsBoot -> Just iface- | mi_boot iface == NotBoot -> Just iface- | otherwise -> Nothing- where- iface = hm_iface hm_info-+upsweep_mod hsc_env mHscMessage old_hmi summary mod_index nmods = do hmi <- compileOne' mHscMessage hsc_env summary- mod_index nmods mb_old_iface (old_hmi >>= hm_linkable)+ mod_index nmods (hm_iface <$> old_hmi) (old_hmi >>= hm_linkable) -- MP: This is a bit janky, because before you add the entries you have to extend the HPT with the module -- you just compiled. Another option, would be delay adding anything until after upsweep has finished, but I@@ -1254,8 +1248,6 @@ Following this fix, GHC can compile itself with --make -O2. -} --- NB: sometimes mods has duplicates; this is harmless because--- any duplicates get clobbered in addListToHpt and never get forced. typecheckLoop :: HscEnv -> [HomeModInfo] -> IO [(ModuleName, HomeModInfo)] typecheckLoop hsc_env hmis = do debugTraceMsg logger 2 $@@ -1264,6 +1256,8 @@ let new_hpt = addListToHpt old_hpt new_mods let new_hsc_env = hscUpdateHPT (const new_hpt) hsc_env -- Crucial, crucial: initIfaceLoad clears the if_rec_types field.+ -- See [KnotVars invariants]+ -- Note [GHC Heap Invariants] mds <- initIfaceLoad new_hsc_env $ mapM (typecheckIface . hm_iface) hmis let new_mods = [ (mn,hmi{ hm_details = details })@@ -1273,7 +1267,10 @@ where logger = hsc_logger hsc_env- old_hpt = hsc_HPT hsc_env+ to_delete = (map (moduleName . mi_module . hm_iface) hmis)+ -- Filter out old modules before tying the knot, otherwise we can end+ -- up with a thunk which keeps reference to the old HomeModInfo.+ !old_hpt = foldl' delFromHpt (hsc_HPT hsc_env) to_delete -- --------------------------------------------------------------------------- --@@ -1447,9 +1444,11 @@ -- | Efficiently construct a map from a NodeKey to its list of transitive dependencies mkDepsMap :: [ModuleGraphNode] -> (NodeKey -> [NodeKey])-mkDepsMap nodes nk =- let (mg, lookup_node) = moduleGraphNodes False nodes- in map (mkNodeKey . node_payload) $ outgoingG mg (expectJust "mkDepsMap" (lookup_node nk))+mkDepsMap nodes =+ -- Important that we force this before returning a lambda so we can share the module graph+ -- for each node+ let !(mg, lookup_node) = moduleGraphNodes False nodes+ in \nk -> map (mkNodeKey . node_payload) $ outgoingG mg (expectJust "mkDepsMap" (lookup_node nk)) -- | If there are {-# SOURCE #-} imports between strongly connected -- components in the topological sort, then those imports can@@ -1660,27 +1659,26 @@ tn <- newTempName logger tmpfs (tmpDir dflags) staticLife suf let dyn_tn = tn -<.> dynsuf addFilesToClean tmpfs dynLife [dyn_tn]- return tn+ return (tn, dyn_tn) -- We don't want to create .o or .hi files unless we have been asked -- to by the user. But we need them, so we patch their locations in -- the ModSummary with temporary files. --- (hi_file, o_file) <-+ ((hi_file, dyn_hi_file), (o_file, dyn_o_file)) <- -- If ``-fwrite-interface` is specified, then the .o and .hi files -- are written into `-odir` and `-hidir` respectively. #16670 if gopt Opt_WriteInterface dflags- then return (ml_hi_file ms_location, ml_obj_file ms_location)+ then return ((ml_hi_file ms_location, ml_dyn_hi_file ms_location)+ , (ml_obj_file ms_location, ml_dyn_obj_file ms_location)) else (,) <$> (new_temp_file (hiSuf_ dflags) (dynHiSuf_ dflags)) <*> (new_temp_file (objectSuf_ dflags) (dynObjectSuf_ dflags)) let ms' = ms { ms_location =- ms_location {ml_hi_file = hi_file, ml_obj_file = o_file}- , ms_hspp_opts = updOptLevel 0 $- setOutputFile (Just o_file) $- setDynOutputFile (Just $ dynamicOutputFile dflags o_file) $- setOutputHi (Just hi_file) $- setDynOutputHi (Just $ dynamicOutputHi dflags hi_file) $- dflags {backend = bcknd}+ ms_location { ml_hi_file = hi_file+ , ml_obj_file = o_file+ , ml_dyn_hi_file = dyn_hi_file+ , ml_dyn_obj_file = dyn_o_file }+ , ms_hspp_opts = updOptLevel 0 $ dflags {backend = bcknd} } pure (ExtendedModSummary ms' bkp_deps) | otherwise = return (ExtendedModSummary ms bkp_deps)@@ -1797,7 +1795,7 @@ let fopts = initFinderOpts (hsc_dflags hsc_env) -- Make a ModLocation for this file- location <- liftIO $ mkHomeModLocation fopts pi_mod_name src_fn+ let location = mkHomeModLocation fopts pi_mod_name src_fn -- Tell the Finder cache where it is, so that subsequent calls -- to findModule will find it, even if it's not on any search path@@ -1912,7 +1910,7 @@ | otherwise = find_it where dflags = hsc_dflags hsc_env- fopts = initFinderOpts dflags+ fopts = initFinderOpts dflags home_unit = hsc_home_unit hsc_env fc = hsc_FC hsc_env units = hsc_units hsc_env@@ -1924,7 +1922,7 @@ old_summary location find_it = do- found <- findImportedModule fc fopts units home_unit wanted_mod Nothing+ found <- findImportedModule fc fopts units home_unit wanted_mod NoPkgQual case found of Found location mod | isJust (ml_hs_file location) ->@@ -2003,9 +2001,8 @@ makeNewModSummary :: HscEnv -> MakeNewModSummary -> IO ExtendedModSummary makeNewModSummary hsc_env MakeNewModSummary{..} = do let PreprocessedImports{..} = nms_preimps- let dflags = hsc_dflags hsc_env obj_timestamp <- modificationTimeIfExists (ml_obj_file nms_location)- dyn_obj_timestamp <- modificationTimeIfExists (dynamicOutputFile dflags (ml_obj_file nms_location))+ dyn_obj_timestamp <- modificationTimeIfExists (ml_dyn_obj_file nms_location) hi_timestamp <- modificationTimeIfExists (ml_hi_file nms_location) hie_timestamp <- modificationTimeIfExists (ml_hie_file nms_location) @@ -2025,8 +2022,8 @@ , ms_srcimps = pi_srcimps , ms_ghc_prim_import = pi_ghc_prim_import , ms_textual_imps =- extra_sig_imports ++- ((,) Nothing . noLoc <$> implicit_sigs) +++ ((,) NoPkgQual . noLoc <$> extra_sig_imports) +++ ((,) NoPkgQual . noLoc <$> implicit_sigs) ++ pi_theimps , ms_hs_hash = nms_src_hash , ms_iface_date = hi_timestamp@@ -2040,8 +2037,8 @@ data PreprocessedImports = PreprocessedImports { pi_local_dflags :: DynFlags- , pi_srcimps :: [(Maybe FastString, Located ModuleName)]- , pi_theimps :: [(Maybe FastString, Located ModuleName)]+ , pi_srcimps :: [(PkgQual, Located ModuleName)]+ , pi_theimps :: [(PkgQual, Located ModuleName)] , pi_ghc_prim_import :: Bool , pi_hspp_fn :: FilePath , pi_hspp_buf :: StringBuffer@@ -2062,12 +2059,16 @@ (pi_local_dflags, pi_hspp_fn) <- ExceptT $ preprocess hsc_env src_fn (fst <$> maybe_buf) mb_phase pi_hspp_buf <- liftIO $ hGetStringBuffer pi_hspp_fn- (pi_srcimps, pi_theimps, pi_ghc_prim_import, L pi_mod_name_loc pi_mod_name)+ (pi_srcimps', pi_theimps', pi_ghc_prim_import, L pi_mod_name_loc pi_mod_name) <- ExceptT $ do let imp_prelude = xopt LangExt.ImplicitPrelude pi_local_dflags popts = initParserOpts pi_local_dflags mimps <- getImports popts imp_prelude pi_hspp_buf pi_hspp_fn src_fn return (first (mkMessages . fmap mkDriverPsHeaderMessage . getMessages) mimps)+ let rn_pkg_qual = renameRawPkgQual (hsc_unit_env hsc_env)+ let rn_imps = fmap (first rn_pkg_qual)+ let pi_srcimps = rn_imps pi_srcimps'+ let pi_theimps = rn_imps pi_theimps' return PreprocessedImports {..} @@ -2229,9 +2230,8 @@ _ -> errorMsg lcl_logger (text (show exc)) return Nothing -withParLog :: Int -> (HscEnv -> RunMakeM a) -> RunMakeM a-withParLog k cont = do- MakeEnv{lqq_var, hsc_env} <- ask+withParLog :: TVar LogQueueQueue -> Int -> ((Logger -> Logger) -> RunMakeM b) -> RunMakeM b+withParLog lqq_var k cont = do let init_log = liftIO $ do -- Make a new log queue lq <- newLogQueue k@@ -2239,9 +2239,13 @@ atomically $ initLogQueue lqq_var lq return lq finish_log lq = liftIO (finishLogQueue lq)- MC.bracket init_log finish_log $ \lq -> do- -- Modify the logger to use the log queue- let lcl_logger = pushLogHook (const (parLogAction lq)) (hsc_logger hsc_env)+ MC.bracket init_log finish_log $ \lq -> cont (pushLogHook (const (parLogAction lq)))++withLoggerHsc :: Int -> (HscEnv -> RunMakeM a) -> RunMakeM a+withLoggerHsc k cont = do+ MakeEnv{withLogger, hsc_env} <- ask+ withLogger k $ \modifyLogger -> do+ let lcl_logger = modifyLogger (hsc_logger hsc_env) hsc_env' = hsc_env { hsc_logger = lcl_logger } -- Run continuation with modified logger cont hsc_env'@@ -2254,7 +2258,7 @@ -> InstantiatedUnit -> RunMakeM () executeInstantiationNode k n wait_deps iu = do- withParLog k $ \hsc_env -> do+ withLoggerHsc k $ \hsc_env -> do -- Wait for the dependencies of this node deps <- wait_deps -- Output of the logger is mediated by a central worker to@@ -2268,11 +2272,12 @@ executeCompileNode :: Int -> Int+ -> Maybe HomeModInfo -> RunMakeM HomePackageTable -> Maybe (ModuleEnv (IORef TypeEnv)) -> ModSummary -> RunMakeM HomeModInfo-executeCompileNode k n wait_deps mknot_var mod = do+executeCompileNode k n !old_hmi wait_deps mknot_var mod = do MakeEnv{..} <- ask let mk_mod = case ms_hsc_src mod of HsigFile ->@@ -2284,7 +2289,7 @@ _ -> return emptyModuleEnv knot_var <- liftIO $ maybe mk_mod return mknot_var deps <- wait_deps- withParLog k $ \hsc_env -> do+ withLoggerHsc k $ \hsc_env -> do let -- Use the cached DynFlags which includes OPTIONS_GHC pragmas lcl_dynflags = ms_hspp_opts mod let lcl_hsc_env =@@ -2295,7 +2300,7 @@ -- Compile the module, locking with a semphore to avoid too many modules -- being compiled at the same time leading to high memory usage. lift $ MaybeT (withAbstractSem compile_sem $ wrapAction lcl_hsc_env $ do- res <- upsweep_mod lcl_hsc_env env_messager old_hpt mod k n+ res <- upsweep_mod lcl_hsc_env env_messager old_hmi mod k n cleanCurrentModuleTempFilesMaybe (hsc_logger hsc_env) (hsc_tmpfs hsc_env) lcl_dynflags return res) @@ -2360,16 +2365,34 @@ self_tid <- CC.myThreadId CC.labelThread self_tid thread_name ++runPipelines :: Int -> HscEnv -> Maybe Messager -> [MakeAction] -> IO ()+runPipelines n_job orig_hsc_env mHscMessager all_pipelines = do+ liftIO $ label_self "main --make thread"++ plugins_hsc_env <- initializePlugins orig_hsc_env Nothing+ case n_job of+ 1 -> runSeqPipelines plugins_hsc_env mHscMessager all_pipelines+ _n -> runParPipelines n_job plugins_hsc_env mHscMessager all_pipelines++runSeqPipelines :: HscEnv -> Maybe Messager -> [MakeAction] -> IO ()+runSeqPipelines plugin_hsc_env mHscMessager all_pipelines =+ let env = MakeEnv { hsc_env = plugin_hsc_env+ , withLogger = \_ k -> k id+ , compile_sem = AbstractSem (return ()) (return ())+ , env_messager = mHscMessager+ }+ in runAllPipelines 1 env all_pipelines++ -- | Build and run a pipeline-runPipelines :: Int -- ^ How many capabilities to use+runParPipelines :: Int -- ^ How many capabilities to use -> HscEnv -- ^ The basic HscEnv which is augmented with specific info for each module- -> HomePackageTable -- ^ The old HPT which is used as a cache (TODO: The cache should be from the ActionMap) -> Maybe Messager -- ^ Optional custom messager to use to report progress -> [MakeAction] -- ^ The build plan for all the module nodes -> IO ()-runPipelines n_jobs orig_hsc_env old_hpt mHscMessager all_pipelines = do+runParPipelines n_jobs plugin_hsc_env mHscMessager all_pipelines = do - liftIO $ label_self "main --make thread" -- A variable which we write to when an error has happened and we have to tell the -- logging thread to gracefully shut down.@@ -2378,13 +2401,12 @@ -- will add it's LogQueue into this queue. log_queue_queue_var <- newTVarIO newLogQueueQueue -- Thread which coordinates the printing of logs- wait_log_thread <- logThread (hsc_logger orig_hsc_env) stopped_var log_queue_queue_var+ wait_log_thread <- logThread (hsc_logger plugin_hsc_env) stopped_var log_queue_queue_var - plugins_hsc_env <- initializePlugins orig_hsc_env Nothing -- Make the logger thread-safe, in case there is some output which isn't sent via the LogQueue.- thread_safe_logger <- liftIO $ makeThreadSafe (hsc_logger orig_hsc_env)- let thread_safe_hsc_env = plugins_hsc_env { hsc_logger = thread_safe_logger }+ thread_safe_logger <- liftIO $ makeThreadSafe (hsc_logger plugin_hsc_env)+ let thread_safe_hsc_env = plugin_hsc_env { hsc_logger = thread_safe_logger } let updNumCapabilities = liftIO $ do n_capabilities <- getNumCapabilities@@ -2401,16 +2423,11 @@ atomically $ writeTVar stopped_var True wait_log_thread - abstract_sem <-- case n_jobs of- 1 -> return $ AbstractSem (return ()) (return ())- _ -> do- compile_sem <- newQSem n_jobs- return $ AbstractSem (waitQSem compile_sem) (signalQSem compile_sem)+ compile_sem <- newQSem n_jobs+ let abstract_sem = AbstractSem (waitQSem compile_sem) (signalQSem compile_sem) -- Reset the number of capabilities once the upsweep ends. let env = MakeEnv { hsc_env = thread_safe_hsc_env- , old_hpt = old_hpt- , lqq_var = log_queue_queue_var+ , withLogger = withParLog log_queue_queue_var , compile_sem = abstract_sem , env_messager = mHscMessager }@@ -2466,3 +2483,31 @@ waitMakeAction :: MakeAction -> IO () waitMakeAction (MakeAction _ mvar) = () <$ readMVar mvar++{- Note [GHC Heap Invariants]++This note is a general place to explain some of the heap invariants which should+hold for a program compiled with --make mode. These invariants are all things+which can be checked easily using ghc-debug.++1. No HomeModInfo are reachable via the EPS.+ Why? Interfaces are lazily loaded into the EPS and the lazy thunk retains+ a reference to the entire HscEnv, if we are not careful the HscEnv will+ contain the HomePackageTable at the time the interface was loaded and+ it will never be released.+ Where? dontLeakTheHPT in GHC.Iface.Load++2. No KnotVars are live at the end of upsweep (#20491)+ Why? KnotVars contains an old stale reference to the TypeEnv for modules+ which participate in a loop. At the end of a loop all the KnotVars references+ should be removed by the call to typecheckLoop.+ Where? typecheckLoop in GHC.Driver.Make.++3. Immediately after a reload, no ModDetails are live.+ Why? During the upsweep all old ModDetails are replaced with a new ModDetails+ generated from a ModIface. If we don't clear the ModDetails before the+ reload takes place then memory usage during the reload is twice as much+ as it should be as we retain a copy of the ModDetails for too long.+ Where? pruneCache in GHC.Driver.Make++-}
compiler/GHC/Driver/MakeFile.hs view
@@ -30,8 +30,8 @@ import GHC.Utils.Panic.Plain import GHC.Types.SourceError import GHC.Types.SrcLoc+import GHC.Types.PkgQual import Data.List (partition)-import GHC.Data.FastString import GHC.Utils.TmpFs import GHC.Iface.Load (cannotFindModule)@@ -284,7 +284,7 @@ findDependency :: HscEnv -> SrcSpan- -> Maybe FastString -- package qualifier, if any+ -> PkgQual -- package qualifier, if any -> ModuleName -- Imported module -> IsBootInterface -- Source import -> Bool -- Record dependency on package modules
compiler/GHC/Driver/Pipeline.hs view
@@ -239,12 +239,12 @@ plugin_hsc_env <- initializePlugins hsc_env (Just (ms_mnwib summary)) let pipe_env = mkPipeEnv NoStop input_fn pipelineOutput- status <- hscRecompStatus mHscMessage plugin_hsc_env summary+ status <- hscRecompStatus mHscMessage plugin_hsc_env upd_summary mb_old_iface mb_old_linkable (mod_index, nmods)- let pipeline = hscPipeline pipe_env (setDumpPrefix pipe_env plugin_hsc_env, summary, status)+ let pipeline = hscPipeline pipe_env (setDumpPrefix pipe_env plugin_hsc_env, upd_summary, status) (iface, linkable) <- runPipeline (hsc_hooks hsc_env) pipeline -- See Note [ModDetails and --make mode]- details <- initModDetails plugin_hsc_env summary iface+ details <- initModDetails plugin_hsc_env upd_summary iface return $! HomeModInfo iface details linkable where lcl_dflags = ms_hspp_opts summary@@ -303,6 +303,7 @@ | otherwise = (backend dflags, dflags2) dflags = dflags3 { includePaths = addImplicitQuoteInclude old_paths [current_dir] }+ upd_summary = summary { ms_hspp_opts = dflags } hsc_env = hscSetFlags dflags hsc_env0 -- ---------------------------------------------------------------------------@@ -432,7 +433,7 @@ let getOfiles LM{ linkableUnlinked } = map nameOfObject (filter isObject linkableUnlinked) obj_files = concatMap getOfiles linkables platform = targetPlatform dflags- exe_file = exeFileName platform staticLink (outputFile dflags)+ exe_file = exeFileName platform staticLink (outputFile_ dflags) linking_needed <- linkingNeeded logger dflags unit_env staticLink linkables pkg_deps @@ -469,7 +470,7 @@ -- 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)+ exe_file = exeFileName platform staticLink (outputFile_ dflags) e_exe_time <- tryIO $ getModificationUTCTime exe_file case e_exe_time of Left _ -> return True@@ -530,11 +531,13 @@ dflags = hsc_dflags hsc_env mb_o_file = outputFile dflags ghc_link = ghcLink dflags -- Set by -c or -no-link-+ notStopPreprocess | StopPreprocess <- stop_phase = False+ | _ <- stop_phase = True -- When linking, the -o argument refers to the linker's output. -- otherwise, we use it as the name for the pipeline's output. output- | NoBackend <- backend dflags = NoOutputFile+ | NoBackend <- backend dflags, notStopPreprocess = NoOutputFile+ -- avoid -E -fno-code undesirable interactions. see #20439 | NoStop <- stop_phase, not (isNoLink ghc_link) = Persistent -- -o foo applies to linker | isJust mb_o_file = SpecificFile@@ -715,67 +718,10 @@ let hsc_env' = hscSetFlags dflags hsc_env (hsc_env_with_plugins, mod_sum, hsc_recomp_status) <- use (T_HscRecomp pipe_env hsc_env' input_fn src_flavour)- res <- hscPipeline pipe_env (hsc_env_with_plugins, mod_sum, hsc_recomp_status)- checkDynamicToo pipe_env hsc_env pp_fn src_flavour res- -- Once the pipeline has finished, check to see if -dynamic-too failed and- -- rerun again if it failed but just the `--dynamic` way.--checkDynamicToo :: P m => PipeEnv -> HscEnv -> FilePath -> HscSource -> (ModIface, Maybe Linkable) -> m (ModIface, Maybe Linkable)-checkDynamicToo pipe_env hsc_env pp_fn src_flavour res = do- liftIO (dynamicTooState (hsc_dflags hsc_env)) >>= \case- DT_Dont -> return res- DT_Dyn -> return res- DT_OK -> return res- -- If we are compiling a Haskell module with -dynamic-too, we- -- first try the "fast path": that is we compile the non-dynamic- -- version and at the same time we check that interfaces depended- -- on exist both for the non-dynamic AND the dynamic way. We also- -- check that they have the same hash.- -- If they don't, dynamicTooState is set to DT_Failed.- -- See GHC.Iface.Load.checkBuildDynamicToo- -- If they do, in the end we produce both the non-dynamic and- -- dynamic outputs.- --- -- If this "fast path" failed, we execute the whole pipeline- -- again, this time for the dynamic way *only*. To do that we- -- just set the dynamicNow bit from the start to ensure that the- -- dynamic DynFlags fields are used and we disable -dynamic-too- -- (its state is already set to DT_Failed so it wouldn't do much- -- anyway).- DT_Failed- -- NB: Currently disabled on Windows (ref #7134, #8228, and #5987)- | OSMinGW32 <- platformOS (targetPlatform dflags) -> return res- | otherwise -> do- liftIO (debugTraceMsg logger 4- (text "Running the full pipeline again for -dynamic-too"))- hsc_env' <- liftIO (resetHscEnv hsc_env)- fullPipeline pipe_env hsc_env' pp_fn src_flavour- where- dflags = hsc_dflags hsc_env- logger = hsc_logger hsc_env---- | Enable dynamic-too, reset EPS-resetHscEnv :: HscEnv -> IO HscEnv-resetHscEnv hsc_env = do- let dflags0 = flip gopt_unset Opt_BuildDynamicToo- $ setDynamicNow- $ (hsc_dflags hsc_env)- hsc_env' <- newHscEnv dflags0- (dbs,unit_state,home_unit,mconstants) <- initUnits (hsc_logger hsc_env) dflags0 Nothing- dflags1 <- updatePlatformConstants dflags0 mconstants- unit_env0 <- initUnitEnv (ghcNameVersion dflags1) (targetPlatform dflags1)- let unit_env = unit_env0- { ue_home_unit = Just home_unit- , ue_units = unit_state- , ue_unit_dbs = Just dbs- }- let hsc_env'' = hscSetFlags dflags1 $ hsc_env'- { hsc_unit_env = unit_env- }- return hsc_env''+ hscPipeline pipe_env (hsc_env_with_plugins, mod_sum, hsc_recomp_status) -- | Everything after preprocess-hscPipeline :: P m => PipeEnv -> ((HscEnv, ModSummary, HscRecompStatus)) -> m (ModIface, Maybe Linkable)+hscPipeline :: P m => PipeEnv -> ((HscEnv, ModSummary, HscRecompStatus)) -> m (ModIface, Maybe Linkable) hscPipeline pipe_env (hsc_env_with_plugins, mod_sum, hsc_recomp_status) = do case hsc_recomp_status of HscUpToDate iface mb_linkable -> return (iface, mb_linkable)@@ -795,11 +741,9 @@ -- Interpreter -> (,) <$> use (T_IO (mkFullIface hsc_env (hscs_partial_iface result) Nothing)) <*> pure Nothing _ -> do res <- hscGenBackendPipeline pipe_env hsc_env mod_sum result- liftIO (dynamicTooState (hsc_dflags hsc_env)) >>= \case- DT_OK -> do+ when (gopt Opt_BuildDynamicToo (hsc_dflags hsc_env)) $ do let dflags' = setDynamicNow (hsc_dflags hsc_env) -- set "dynamicNow" () <$ hscGenBackendPipeline pipe_env (hscSetFlags dflags' hsc_env) mod_sum result- _ -> return () return res hscGenBackendPipeline :: P m@@ -811,11 +755,7 @@ hscGenBackendPipeline pipe_env hsc_env mod_sum result = do let mod_name = moduleName (ms_mod mod_sum) src_flavour = (ms_hsc_src mod_sum)- dflags = hsc_dflags hsc_env- -- MP: The ModLocation is recalculated here to get the right paths when- -- -dynamic-too is enabled. `ModLocation` should be extended with a field for- -- the location of the `dyn_o` file to avoid this recalculation.- location <- liftIO (getLocation pipe_env dflags src_flavour mod_name)+ let location = ms_location mod_sum (fos, miface, mlinkable, o_file) <- use (T_HscBackend pipe_env hsc_env mod_name src_flavour location result) final_fp <- hscPostBackendPipeline pipe_env hsc_env (ms_hsc_src mod_sum) (backend (hsc_dflags hsc_env)) (Just location) o_file final_linkable <-
compiler/GHC/Driver/Pipeline/Execute.hs view
@@ -81,6 +81,9 @@ import GHC.Utils.Panic import GHC.Unit.Module.Env import GHC.Driver.Env.KnotVars+import GHC.Driver.Config.Finder+import GHC.Rename.Names+import Data.Bifunctor (first) newtype HookedUse a = HookedUse { runHookedUse :: (Hooks, PhaseHook) -> IO a } deriving (Functor, Applicative, Monad, MonadIO, MonadThrow, MonadCatch) via (ReaderT (Hooks, PhaseHook) IO)@@ -494,7 +497,7 @@ runHscBackendPhase pipe_env hsc_env mod_name src_flavour location result = do let dflags = hsc_dflags hsc_env logger = hsc_logger hsc_env- o_file = ml_obj_file location -- The real object file+ o_file = if dynamicNow dflags then ml_dyn_obj_file location else ml_obj_file location -- The real object file next_phase = hscPostBackendPhase src_flavour (backend dflags) case result of HscUpdate iface ->@@ -635,25 +638,27 @@ -- gather the imports and module name (hspp_buf,mod_name,imps,src_imps, ghc_prim_imp) <- do- buf <- hGetStringBuffer input_fn- let imp_prelude = xopt LangExt.ImplicitPrelude dflags- popts = initParserOpts dflags- eimps <- getImports popts imp_prelude buf input_fn (basename <.> suff)- case eimps of- Left errs -> throwErrors (GhcPsMessage <$> errs)- Right (src_imps,imps, ghc_prim_imp, L _ mod_name) -> return- (Just buf, mod_name, imps, src_imps, ghc_prim_imp)+ buf <- hGetStringBuffer input_fn+ let imp_prelude = xopt LangExt.ImplicitPrelude dflags+ popts = initParserOpts dflags+ rn_pkg_qual = renameRawPkgQual (hsc_unit_env hsc_env)+ rn_imps = fmap (first rn_pkg_qual)+ eimps <- getImports popts imp_prelude buf input_fn (basename <.> suff)+ case eimps of+ Left errs -> throwErrors (GhcPsMessage <$> errs)+ Right (src_imps,imps, ghc_prim_imp, L _ mod_name) -> return+ (Just buf, mod_name, rn_imps imps, rn_imps src_imps, ghc_prim_imp) -- Take -o into account if present -- Very like -ohi, but we must *only* do this if we aren't linking -- (If we're linking then the -o applies to the linked thing, not to -- the object file for one module.) -- Note the nasty duplication with the same computation in compileFile above- location <- getLocation pipe_env dflags src_flavour mod_name+ location <- mkOneShotModLocation pipe_env dflags src_flavour mod_name let o_file = ml_obj_file location -- The real object file hi_file = ml_hi_file location hie_file = ml_hie_file location- dyn_o_file = dynamicOutputFile dflags o_file+ dyn_o_file = ml_dyn_obj_file location src_hash <- getFileHash (basename <.> suff) hi_date <- modificationTimeIfExists hi_file@@ -702,6 +707,52 @@ return (plugin_hsc_env, mod_summary, status) +-- | Calculate the ModLocation from the provided DynFlags. This function is only used+-- in one-shot mode and therefore takes into account the effect of -o/-ohi flags+-- (which do nothing in --make mode)+mkOneShotModLocation :: PipeEnv -> DynFlags -> HscSource -> ModuleName -> IO ModLocation+mkOneShotModLocation pipe_env dflags src_flavour mod_name = do+ let PipeEnv{ src_basename=basename,+ src_suffix=suff } = pipe_env+ let location1 = mkHomeModLocation2 fopts mod_name basename suff++ -- Boot-ify it if necessary+ let location2+ | HsBootFile <- src_flavour = addBootSuffixLocnOut location1+ | otherwise = location1+++ -- Take -ohi into account if present+ -- This can't be done in mkHomeModuleLocation because+ -- it only applies to the module being compiles+ let ohi = outputHi dflags+ location3 | Just fn <- ohi = location2{ ml_hi_file = fn }+ | otherwise = location2++ let dynohi = dynOutputHi dflags+ location4 | Just fn <- dynohi = location3{ ml_dyn_hi_file = fn }+ | otherwise = location3++ -- Take -o into account if present+ -- Very like -ohi, but we must *only* do this if we aren't linking+ -- (If we're linking then the -o applies to the linked thing, not to+ -- the object file for one module.)+ -- Note the nasty duplication with the same computation in compileFile+ -- above+ let expl_o_file = outputFile_ dflags+ expl_dyn_o_file = dynOutputFile_ dflags+ location5 | Just ofile <- expl_o_file+ , let dyn_ofile = fromMaybe (ofile -<.> dynObjectSuf_ dflags) expl_dyn_o_file+ , isNoLink (ghcLink dflags)+ = location4 { ml_obj_file = ofile+ , ml_dyn_obj_file = dyn_ofile }+ | Just dyn_ofile <- expl_dyn_o_file+ = location4 { ml_dyn_obj_file = dyn_ofile }+ | otherwise = location4+ return location5+ where+ fopts = initFinderOpts dflags+ runHscTcPhase :: HscEnv -> ModSummary -> IO (FrontendResult, Messages GhcMessage) runHscTcPhase = hscTypecheckAndGetWarnings @@ -728,7 +779,11 @@ ] ) return output_fn -phaseOutputFilenameNew :: Phase -> PipeEnv -> HscEnv -> Maybe ModLocation -> IO FilePath+phaseOutputFilenameNew :: Phase -- ^ The next phase+ -> PipeEnv+ -> HscEnv+ -> Maybe ModLocation -- ^ A ModLocation, if we are compiling a Haskell source file+ -> IO FilePath phaseOutputFilenameNew next_phase pipe_env hsc_env maybe_loc = do let PipeEnv{stop_phase, src_basename, output_spec} = pipe_env let dflags = hsc_dflags hsc_env@@ -764,16 +819,37 @@ -> Maybe ModLocation -> IO FilePath getOutputFilename logger tmpfs stop_phase output basename dflags next_phase maybe_location+ -- 1. If we are generating object files for a .hs file, then return the odir as the ModLocation+ -- will have been modified to point to the accurate locations+ | StopLn <- next_phase, Just loc <- maybe_location =+ return $ if dynamicNow dflags then ml_dyn_obj_file loc+ else ml_obj_file loc+ -- 2. If output style is persistant then | is_last_phase, Persistent <- output = persistent_fn- | is_last_phase, SpecificFile <- output = case outputFile dflags of- Just f -> return f- Nothing ->- panic "SpecificFile: No filename"+ -- 3. Specific file is only set when outputFile is set by -o+ -- If we are in dynamic mode but -dyno is not set then write to the same path as+ -- -o with a .dyn_* extension. This case is not triggered for object files which+ -- are always handled by the ModLocation.+ | is_last_phase, SpecificFile <- output =+ return $+ if dynamicNow dflags+ then case dynOutputFile_ dflags of+ Nothing -> let ofile = getOutputFile_ dflags+ new_ext = case takeExtension ofile of+ "" -> "dyn"+ ext -> "dyn_" ++ tail ext+ in replaceExtension ofile new_ext+ Just fn -> fn+ else getOutputFile_ dflags | keep_this_output = persistent_fn | Temporary lifetime <- output = newTempName logger tmpfs (tmpDir dflags) lifetime suffix | otherwise = newTempName logger tmpfs (tmpDir dflags) TFL_CurrentModule suffix where+ getOutputFile_ dflags = case outputFile_ dflags of+ Nothing -> pprPanic "SpecificFile: No filename" (ppr $ (dynamicNow dflags, outputFile_ dflags, dynOutputFile_ dflags))+ Just fn -> fn+ hcsuf = hcSuf dflags odir = objectDir dflags osuf = objectSuf dflags@@ -808,7 +884,6 @@ persistent = basename <.> suffix odir_persistent- | Just loc <- maybe_location = ml_obj_file loc | Just d <- odir = (d </> persistent) | otherwise = persistent
compiler/GHC/Hs/Syn/Type.hs view
@@ -181,7 +181,7 @@ where go WpHole = id go (w1 `WpCompose` w2) = go w1 . go w2- go (WpFun _ w2 (Scaled m exp_arg) _) = liftPRType $ \t ->+ go (WpFun _ w2 (Scaled m exp_arg)) = liftPRType $ \t -> let act_res = funResultTy t exp_res = hsWrapperType w2 act_res in mkFunctionType m exp_arg exp_res
compiler/GHC/HsToCore.hs view
@@ -648,7 +648,7 @@ (x |> (GRefl :: a ~# (a |> TYPE co1)) ; co2) It looks like we can write this in Haskell directly, but we can't:-the reprsentation polymorphism checks defeat us. Note that `x` is a+the representation polymorphism checks defeat us. Note that `x` is a representation-polymorphic variable. So we must wire it in with a compulsory unfolding, like other representation-polymorphic primops. @@ -755,10 +755,13 @@ info = noCafIdInfo `setInlinePragInfo` alwaysInlinePragma `setUnfoldingInfo` mkCompulsoryUnfolding' rhs+ `setArityInfo` arity ty = mkSpecForAllTys [ runtimeRep1TyVar, runtimeRep2TyVar , openAlphaTyVar, openBetaTyVar ] $ mkVisFunTyMany openAlphaTy openBetaTy++ arity = 1 id = mkExportedVanillaId unsafeCoercePrimName ty `setIdInfo` info ; return (id, old_expr) }
compiler/GHC/HsToCore/Arrows.hs view
@@ -27,13 +27,11 @@ -- So WATCH OUT; check each use of split*Ty functions. -- Sigh. This is a pain. -import {-# SOURCE #-} GHC.HsToCore.Expr ( dsExpr, dsLExpr, dsLExprNoLP, dsLocalBinds,+import {-# SOURCE #-} GHC.HsToCore.Expr ( dsExpr, dsLExpr, dsLocalBinds, dsSyntaxExpr ) import GHC.Tc.Utils.TcType-import GHC.Core.Type( splitPiTy ) import GHC.Core.Multiplicity-import GHC.Tc.Errors.Types ( LevityCheckProvenance(..) ) import GHC.Tc.Types.Evidence import GHC.Core import GHC.Core.FVs@@ -75,25 +73,6 @@ the_choice_id = assocMaybe prs choiceAName the_loop_id = assocMaybe prs loopAName - -- used as an argument in, e.g., do_premap- ; check_lev_poly 3 the_arr_id-- -- used as an argument in, e.g., dsCmdStmt/BodyStmt- ; check_lev_poly 5 the_compose_id-- -- used as an argument in, e.g., dsCmdStmt/BodyStmt- ; check_lev_poly 4 the_first_id-- -- the result of the_app_id is used as an argument in, e.g.,- -- dsCmd/HsCmdArrApp/HsHigherOrderApp- ; check_lev_poly 2 the_app_id-- -- used as an argument in, e.g., HsCmdIf- ; check_lev_poly 5 the_choice_id-- -- used as an argument in, e.g., RecStmt- ; check_lev_poly 4 the_loop_id- ; return (meth_binds, DsCmdEnv { arr_id = Var (unmaybe the_arr_id arrAName), compose_id = Var (unmaybe the_compose_id composeAName),@@ -112,20 +91,6 @@ unmaybe Nothing name = pprPanic "mkCmdEnv" (text "Not found:" <+> ppr name) unmaybe (Just id) _ = id - -- returns the result type of a pi-type (that is, a forall or a function)- -- Note that this result type may be ill-scoped.- res_type :: Type -> Type- res_type ty = res_ty- where- (_, res_ty) = splitPiTy ty-- check_lev_poly :: Int -- arity- -> Maybe Id -> DsM ()- check_lev_poly _ Nothing = return ()- check_lev_poly arity (Just id)- = dsNoLevPoly (nTimes arity res_type (idType id)) (LevityCheckMkCmdEnv id)-- -- arr :: forall b c. (b -> c) -> a b c do_arr :: DsCmdEnv -> Type -> Type -> CoreExpr -> CoreExpr do_arr ids b_ty c_ty f = mkApps (arr_id ids) [Type b_ty, Type c_ty, f]@@ -319,9 +284,9 @@ let env_ty = mkBigCoreVarTupTy env_ids let env_stk_ty = mkCorePairTy env_ty unitTy let env_stk_expr = mkCorePairExpr (mkBigCoreVarTup env_ids) mkCoreUnitExpr- fail_expr <- mkFailExpr ProcExpr env_stk_ty+ fail_expr <- mkFailExpr (ArrowMatchCtxt ProcExpr) env_stk_ty var <- selectSimpleMatchVarL Many pat- match_code <- matchSimply (Var var) ProcExpr pat env_stk_expr fail_expr+ 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 (Lam var match_code)@@ -367,7 +332,7 @@ let (a_arg_ty, _res_ty') = tcSplitAppTy arrow_ty (_a_ty, arg_ty) = tcSplitAppTy a_arg_ty- core_arrow <- dsLExprNoLP arrow+ core_arrow <- dsLExpr arrow core_arg <- dsLExpr arg stack_id <- newSysLocalDs Many stack_ty core_make_arg <- matchEnvStack env_ids stack_id core_arg@@ -423,7 +388,7 @@ (core_cmd, free_vars, env_ids') <- dsfixCmd ids local_vars stack_ty' res_ty cmd stack_id <- newSysLocalDs Many stack_ty- arg_id <- newSysLocalDsNoLP Many arg_ty+ arg_id <- newSysLocalDs Many arg_ty -- push the argument expression onto the stack let stack' = mkCorePairExpr (Var arg_id) (Var stack_id)@@ -628,11 +593,7 @@ -- -- ---> premap (\ (env,stk) -> env) c -dsCmd ids local_vars stack_ty res_ty do_block@(HsCmdDo stmts_ty- (L loc stmts))- env_ids = do- putSrcSpanDsA loc $- dsNoLevPoly stmts_ty (LevityCheckDoCmd do_block)+dsCmd ids local_vars stack_ty res_ty (HsCmdDo _ (L _ stmts)) env_ids = do (core_stmts, env_ids') <- dsCmdDo ids local_vars res_ty stmts env_ids let env_ty = mkBigCoreVarTupTy env_ids core_fst <- mkFstExpr env_ty stack_ty@@ -702,8 +663,7 @@ DIdSet, -- subset of local vars that occur free [Id]) -- the same local vars as a list, fed back dsfixCmd ids local_vars stk_ty cmd_ty cmd- = do { putSrcSpanDs (getLocA cmd) $ dsNoLevPoly cmd_ty (LevityCheckDesugaringCmd cmd)- ; trimInput (dsLCmd ids local_vars stk_ty cmd_ty cmd) }+ = trimInput (dsLCmd ids local_vars stk_ty cmd_ty cmd) -- Feed back the list of local variables actually used a command, -- for use as the input tuple of the generated arrow.@@ -744,7 +704,7 @@ (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 (newSysLocalDsNoLP Many) pat_tys+ param_ids <- mapM (newSysLocalDs Many) pat_tys stack_id' <- newSysLocalDs Many stack_ty' -- the expression is built from the inside out, so the actions@@ -755,9 +715,9 @@ in_ty = envStackType env_ids stack_ty in_ty' = envStackType env_ids' stack_ty' - fail_expr <- mkFailExpr LambdaExpr in_ty'+ fail_expr <- mkFailExpr (ArrowMatchCtxt KappaExpr) in_ty' -- match the patterns against the parameters- match_code <- matchSimplys (map Var param_ids) LambdaExpr pats core_expr+ match_code <- matchSimplys (map Var param_ids) (ArrowMatchCtxt KappaExpr) pats core_expr fail_expr -- match the parameters against the top of the old stack (stack_id, param_code) <- matchVarStack param_ids stack_id' match_code@@ -790,8 +750,7 @@ -- -- ---> premap (\ (xs) -> ((xs), ())) c -dsCmdDo ids local_vars res_ty [L loc (LastStmt _ body _ _)] env_ids = do- putSrcSpanDsA loc $ dsNoLevPoly res_ty (LevityCheckInCmd body)+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@@ -859,7 +818,6 @@ out_ty = mkBigCoreVarTupTy out_ids before_c_ty = mkCorePairTy in_ty1 out_ty after_c_ty = mkCorePairTy c_ty out_ty- dsNoLevPoly c_ty LevityCheckCmdStmt snd_fn <- mkSndExpr c_ty out_ty return (do_premap ids in_ty before_c_ty out_ty core_mux $ do_compose ids before_c_ty after_c_ty out_ty
compiler/GHC/HsToCore/Binds.hs view
@@ -1118,16 +1118,13 @@ ; return (w1 . w2) } -- See comments on WpFun in GHC.Tc.Types.Evidence for an explanation of what -- the specification of this clause is-dsHsWrapper (WpFun c1 c2 (Scaled w t1) doc)- = do { x <- newSysLocalDsNoLP w t1+dsHsWrapper (WpFun c1 c2 (Scaled w t1))+ = do { x <- newSysLocalDs w t1 ; w1 <- dsHsWrapper c1 ; w2 <- dsHsWrapper c2 ; let app f a = mkCoreAppDs (text "dsHsWrapper") f a arg = w1 (Var x)- ; (_, ok) <- askNoErrsDs $ dsNoLevPolyExpr arg (LevityCheckWpFun doc)- ; if ok- then return (\e -> (Lam x (w2 (app e arg))))- else return id } -- this return is irrelevant+ ; return (\e -> (Lam x (w2 (app e arg)))) } dsHsWrapper (WpCast co) = assert (coercionRole co == Representational) $ return $ \e -> mkCastDs e co dsHsWrapper (WpEvApp tm) = do { core_tm <- dsEvTerm tm
compiler/GHC/HsToCore/Expr.hs view
@@ -13,7 +13,7 @@ -} module GHC.HsToCore.Expr- ( dsExpr, dsLExpr, dsLExprNoLP, dsLocalBinds+ ( dsExpr, dsLExpr, dsLocalBinds , dsValBinds, dsLit, dsSyntaxExpr ) where@@ -30,7 +30,6 @@ import GHC.HsToCore.Monad import GHC.HsToCore.Pmc ( addTyCs, pmcGRHSs ) import GHC.HsToCore.Errors.Types-import GHC.Hs.Syn.Type ( hsExprType, hsWrapperType ) import GHC.Types.SourceText import GHC.Types.Name import GHC.Types.Name.Env@@ -241,18 +240,6 @@ dsLExpr (L loc e) = putSrcSpanDsA loc $ dsExpr e --- | Variant of 'dsLExpr' that ensures that the result is not--- representation- polymorphic. This should be used when the resulting--- expression will be an argument to some other function.--- See Note [Representation polymorphism checking] in "GHC.HsToCore.Monad"--- See Note [Representation polymorphism invariants] in "GHC.Core"-dsLExprNoLP :: LHsExpr GhcTc -> DsM CoreExpr-dsLExprNoLP (L loc e)- = putSrcSpanDsA loc $- do { e' <- dsExpr e- ; dsNoLevPolyExpr e' (LevityCheckHsExpr e)- ; return e' }- dsExpr :: HsExpr GhcTc -> DsM CoreExpr dsExpr (HsVar _ (L _ id)) = dsHsVar id dsExpr (HsRecSel _ (FieldOcc id _)) = dsHsVar id@@ -279,7 +266,7 @@ = case ext_expr_tc of ExpansionExpr (HsExpanded _ b) -> dsExpr b WrapExpr {} -> dsHsWrapped e- ConLikeTc {} -> dsHsWrapped e+ ConLikeTc con tvs tys -> dsConLike con tvs tys -- Hpc Support HsTick tickish e -> do e' <- dsLExpr e@@ -320,10 +307,8 @@ dsExpr e@(HsApp _ fun arg) = do { fun' <- dsLExpr fun- -- See Note [Desugaring representation-polymorphic applications]- -- in GHC.HsToCore.Utils- ; dsWhenNoErrs (hsExprType e) (dsLExprNoLP arg)- (\arg' -> mkCoreAppDs (text "HsApp" <+> ppr e) fun' arg') }+ ; arg' <- dsLExpr arg+ ; return $ mkCoreAppDs (text "HsApp" <+> ppr e) fun' arg' } dsExpr e@(HsAppType {}) = dsHsWrapped e @@ -345,32 +330,25 @@ converting to core it must become a CO. -} -dsExpr e@(ExplicitTuple _ tup_args boxity)+dsExpr (ExplicitTuple _ tup_args boxity) = do { let go (lam_vars, args) (Missing (Scaled mult ty)) -- For every missing expression, we need -- another lambda in the desugaring.- = do { lam_var <- newSysLocalDsNoLP mult ty+ = do { lam_var <- newSysLocalDs mult ty ; return (lam_var : lam_vars, Var lam_var : args) } go (lam_vars, args) (Present _ expr) -- Expressions that are present don't generate -- lambdas, just arguments.- = do { core_expr <- dsLExprNoLP expr+ = do { core_expr <- dsLExpr expr ; return (lam_vars, core_expr : args) } - -- See Note [Desugaring representation-polymorphic applications]- -- in GHC.HsToCore.Utils- ; dsWhenNoErrs (hsExprType e) (foldM go ([], []) (reverse tup_args))+ ; (lam_vars, args) <- foldM go ([], []) (reverse tup_args) -- The reverse is because foldM goes left-to-right- (\(lam_vars, args) ->- mkCoreLams lam_vars $- mkCoreTupBoxity boxity args) }+ ; return $ mkCoreLams lam_vars (mkCoreTupBoxity boxity args) } -- See Note [Don't flatten tuples from HsSyn] in GHC.Core.Make -dsExpr e@(ExplicitSum types alt arity expr)- -- See Note [Desugaring representation-polymorphic applications]- -- in GHC.HsToCore.Utils- = dsWhenNoErrs (hsExprType e) (dsLExprNoLP expr)- (mkCoreUbxSum arity alt types)+dsExpr (ExplicitSum types alt arity expr)+ = mkCoreUbxSum arity alt types <$> dsLExpr expr dsExpr (HsPragE _ prag expr) = ds_prag_expr prag expr@@ -441,7 +419,7 @@ -} dsExpr (HsStatic _ expr@(L loc _)) = do- expr_ds <- dsLExprNoLP expr+ expr_ds <- dsLExpr expr let ty = exprType expr_ds makeStaticId <- dsLookupGlobalId makeStaticName @@ -495,8 +473,8 @@ mk_arg (arg_ty, fl) = case findField (rec_flds rbinds) (flSelector fl) of- (rhs:rhss) -> assert (null rhss )- dsLExprNoLP rhs+ (rhs:rhss) -> assert (null rhss)+ dsLExpr rhs [] -> mkErrorAppDs rEC_CON_ERROR_ID arg_ty (ppr (flLabel fl)) unlabelled_bottom arg_ty = mkErrorAppDs rEC_CON_ERROR_ID arg_ty Outputable.empty @@ -808,23 +786,7 @@ ; core_arg_wraps <- mapM dsHsWrapper arg_wraps ; core_res_wrap <- dsHsWrapper res_wrap ; let wrapped_args = zipWithEqual "dsSyntaxExpr" ($) core_arg_wraps arg_exprs- -- We need to compute the type of the desugared expression without- -- actually performing the desugaring, which could be problematic- -- in the presence of representation polymorphism.- -- See Note [Desugaring representation-polymorphic applications]- -- in GHC.HsToCore.Utils- expr_type = hsWrapperType res_wrap- (applyTypeToArgs (ppr fun) (exprType fun) wrapped_args)- ; dsWhenNoErrs expr_type- (zipWithM_ dsNoLevPolyExpr wrapped_args [ mk_msg n | n <- [1..] ])- (\_ -> core_res_wrap (mkCoreApps fun wrapped_args)) }- -- Use mkCoreApps instead of mkApps:- -- unboxed types are possible with RebindableSyntax (#19883)- -- This won't be evaluated if there are any- -- representation-polymorphic arguments.-- where- mk_msg n = LevityCheckInSyntaxExpr (DsArgNum n) expr+ ; return $ core_res_wrap (mkCoreApps fun wrapped_args) } dsSyntaxExpr NoSyntaxExprTc _ = panic "dsSyntaxExpr" findField :: [LHsRecField GhcTc arg] -> Name -> [arg]@@ -897,7 +859,7 @@ -- See Note [Desugaring explicit lists] dsExplicitList elt_ty xs = do { dflags <- getDynFlags- ; xs' <- mapM dsLExprNoLP xs+ ; xs' <- mapM dsLExpr xs ; if xs' `lengthExceeds` maxBuildLength -- Don't generate builds if the list is very long. || null xs'@@ -913,25 +875,25 @@ dsArithSeq :: PostTcExpr -> (ArithSeqInfo GhcTc) -> DsM CoreExpr dsArithSeq expr (From from)- = App <$> dsExpr expr <*> dsLExprNoLP from+ = App <$> dsExpr expr <*> dsLExpr from dsArithSeq expr (FromTo from to) = do fam_envs <- dsGetFamInstEnvs dflags <- getDynFlags warnAboutEmptyEnumerations fam_envs dflags from Nothing to expr' <- dsExpr expr- from' <- dsLExprNoLP from- to' <- dsLExprNoLP to+ from' <- dsLExpr from+ to' <- dsLExpr to return $ mkApps expr' [from', to'] dsArithSeq expr (FromThen from thn)- = mkApps <$> dsExpr expr <*> mapM dsLExprNoLP [from, thn]+ = mkApps <$> dsExpr expr <*> mapM dsLExpr [from, thn] dsArithSeq expr (FromThenTo from thn to) = do fam_envs <- dsGetFamInstEnvs dflags <- getDynFlags warnAboutEmptyEnumerations fam_envs dflags from (Just thn) to expr' <- dsExpr expr- from' <- dsLExprNoLP from- thn' <- dsLExprNoLP thn- to' <- dsLExprNoLP to+ from' <- dsLExpr from+ thn' <- dsLExpr thn+ to' <- dsLExpr to return $ mkApps expr' [from', thn', to'] {-@@ -1057,8 +1019,7 @@ -- NB: withDict is always instantiated by a wrapper, so we need -- only check for it in dsHsUnwrapped dsHsVar var- = do { checkLevPolyFunction var var (idType var)- ; return (varToCoreExpr var) } -- See Note [Desugaring vars]+ = return (varToCoreExpr var) -- See Note [Desugaring vars] dsHsConLike :: ConLike -> DsM CoreExpr dsHsConLike (RealDataCon dc)@@ -1131,112 +1092,13 @@ {- ************************************************************************ * *- Representation polymorphism checks+ dsHsWrapped and ds_withDict * * ************************************************************************--Note [Checking for representation-polymorphic functions]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-We cannot have representation-polymorphic function arguments. See-Note [Representation polymorphism invariants] in GHC.Core. That is-checked by dsLExprNoLP.--But what about- const True (unsafeCoerce# :: forall r1 r2 (a :: TYPE r1) (b :: TYPE r2). a -> b)--Since `unsafeCoerce#` has no binding, it has a compulsory unfolding.-But that compulsory unfolding is a representation-polymorphic lambda, which-is no good. So we want to reject this. On the other hand- const True (unsafeCoerce# @LiftedRep @UnliftedRep)-is absolutely fine.--We have to collect all the type-instantiation and *then* check. That-is what dsHsWrapped does. Because we might have an HsVar without a-wrapper, we check in dsHsVar as well. typecheck/should_fail/T17021-triggers this case.--Note that if `f :: forall r (a :: TYPE r). blah`, then- const True f-is absolutely fine. Here `f` is a function, represented by a-pointer, and we can pass it to `const` (or anything else). (See-#12708 for an example.) It's only the Id.hasNoBinding functions-that are a problem. See checkLevPolyFunction.--Interestingly, this approach does not look to see whether the Id in-question will be eta expanded. The logic is this:- * Either the Id in question is saturated or not.- * If it is, then it surely can't have representation-polymorphic arguments.- If its wrapped type contains representation-polymorphic arguments, reject.- * If it's not, then it can't be eta expanded with representation-polymorphic- argument. If its wrapped type contains representation-polymorphic arguments,- reject.-So, either way, we're good to reject.--Note [Nasty wrinkle in representation-polymorphic function check]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-A nasty wrinkle came up in T13244- type family Rep x- type instance Rep Int = IntRep-- type Unboxed x :: TYPE (Rep x)- type instance Unboxed Int = Int#-- box :: Unboxed Int -> Int- box = I#--Here the function I# is wrapped in a /cast/, thus- box = I# |> (co :: (Int# -> Int) ~ (Unboxed Int -> Int))-If we look only at final type of the expression,- namely: Unboxed Int -> Int,-the kind of the argument type is TYPE (Rep Int), and that needs-type-family reduction to determine the runtime representation.--So we split the wrapper into the instantiating part (which is what-we really want) and everything else; see splitWrapper. This is-very disgusting.--But it also improves the error message in an example like T13233_elab:- obscure :: (forall (rep1 :: RuntimeRep) (rep2 :: RuntimeRep)- (a :: TYPE rep1) (b :: TYPE rep2).- a -> b -> (# a, b #)) -> ()- obscure _ = ()-- quux = obscure (#,#)--Around the (#,#) we'll get some type /abstractions/ wrapping some type-/instantiations/. In the representation polymorphism error message,-we really only want to report the instantiations.-Hence passing (mkHsWrap w_inner e) to checkLevPolyArgs.---Note [Checking representation-polymorphic data constructors]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Similarly, generated by a newtype data constructor, we might get this:- (/\(r :: RuntimeRep) (a :: TYPE r) \(x::a). K r a x) @LiftedRep Int 4--which we want to accept. See Note [Typechecking data constructors] in-GHC.Tc.Gen.Head.--Because we want to accept this, we switch off Lint's-representation polymorphism checks when Lint checks the output of the-desugarer; see the lf_check_levity_poly flag in-GHC.Core.Lint.lintCoreBindings.--We can get this situation both for representation-polymorphic-newtype constructors (T18481), and for representation-polymorphic-algebraic data types, e.g (T18481a)- type T :: TYPE (BoxedRep r) -> TYPE (BoxedRep r)- data T a = MkT Int-- f :: T Bool- f = MkT @Lifted @Bool 42 -} ------------------------------ dsHsWrapped :: HsExpr GhcTc -> DsM CoreExpr--- Looks for a function 'f' wrapped in type applications (HsAppType)--- or wrappers (HsWrap), and checks that any hasNoBinding function--- is not representation-polymorphic, *after* instantiation with those wrappers dsHsWrapped orig_hs_expr = go idHsWrapper orig_hs_expr where@@ -1247,31 +1109,18 @@ go wrap (HsAppType ty (L _ hs_e) _) = go (wrap <.> WpTyApp ty) hs_e - go wrap e@(XExpr (ConLikeTc con tvs tys))- = do { let (w_outer, w_inner) = splitWrapper wrap- ; w_outer' <- dsHsWrapper w_outer- ; w_inner' <- dsHsWrapper w_inner- ; ds_con <- dsConLike con tvs tys- ; let inst_e = w_inner' ds_con- inst_ty = exprType inst_e- ; checkLevPolyArgs (mkHsWrap w_inner e) inst_ty- ; return (w_outer' inst_e) }-- go wrap e@(HsVar _ (L _ var))+ go wrap (HsVar _ (L _ var)) | var `hasKey` withDictKey = do { wrap' <- dsHsWrapper wrap ; ds_withDict (exprType (wrap' (varToCoreExpr var))) } | otherwise- = do { let (w_outer, w_inner) = splitWrapper wrap- ; w_outer' <- dsHsWrapper w_outer- ; w_inner' <- dsHsWrapper w_inner- ; let inst_e = w_inner' (varToCoreExpr var)- inst_ty = exprType inst_e- ; checkLevPolyFunction (mkHsWrap w_inner e) var inst_ty+ = do { wrap' <- dsHsWrapper wrap+ ; let expr = wrap' (varToCoreExpr var)+ ty = exprType expr ; dflags <- getDynFlags- ; warnAboutIdentities dflags var inst_ty- ; return (w_outer' inst_e) }+ ; warnAboutIdentities dflags var ty+ ; return expr } go wrap hs_e = do { wrap' <- dsHsWrapper wrap@@ -1279,32 +1128,6 @@ do { e <- dsExpr hs_e ; return (wrap' e) } } -splitWrapper :: HsWrapper -> (HsWrapper, HsWrapper)--- Split a wrapper w into (outer_wrap <.> inner_wrap), where--- inner_wrap does instantiation (type and evidence application)--- and outer_wrap is everything else, such as a final cast--- See Note [Nasty wrinkle in representation-polymorphic function check]-splitWrapper wrap- = go WpHole wrap- where- go :: HsWrapper -> HsWrapper -> (HsWrapper, HsWrapper)- -- If (go w1 w2) = (w3,w4) then- -- - w1 <.> w2 = w3 <.> w4- -- - w4 does instantiation only ("instantiator" below)- -- 'go' mainly dispatches on w2, using w1 as a work-list- -- onto which it pushes stuff in w2 to come back to later- go WpHole WpHole = (WpHole,WpHole)- go w WpHole = splitWrapper w- go w1 (w2 `WpCompose` w3) = go (w1 <.> w2) w3-- go w1 w2 | instantiator w2 = liftSnd (<.> w2) (splitWrapper w1)- | otherwise = (w1 <.> w2, WpHole)-- instantiator (WpTyApp {}) = True- instantiator (WpEvApp {}) = True- instantiator _ = False-- -- See Note [withDict] ds_withDict :: Type -> DsM CoreExpr ds_withDict wrapped_ty@@ -1456,30 +1279,3 @@ error, which is trickier to do with the way that GHC.Core.Opt.ConstantFold is set up. -}---- | Takes a (pretty-printed) expression, a function, and its--- instantiated type. If the function is a hasNoBinding op, and the--- type has representation-polymorphic arguments, issue an error.--- Note [Checking for representation-polymorphic functions]-checkLevPolyFunction :: Outputable e => e -> Id -> Type -> DsM ()-checkLevPolyFunction orig_hs_expr var ty- | hasNoBinding var- = checkLevPolyArgs orig_hs_expr ty- | otherwise- = return ()--checkLevPolyArgs :: Outputable e => e -> Type -> DsM ()--- Check that there are no representation-polymorphic arguments in--- the supplied type--- E.g. Given (forall a. t1 -> t2 -> blah), ensure that t1,t2--- are not representation-polymorhic------ Pass orig_hs_expr, so that the user can see entire thing--- Note [Checking for representation-polymorphic functions]-checkLevPolyArgs orig_hs_expr ty- | let (binders, _) = splitPiTys ty- arg_tys = mapMaybe binderRelevantType_maybe binders- bad_tys = filter isTypeLevPoly arg_tys- , not (null bad_tys)- = diagnosticDs $ DsCannotUseFunWithPolyArgs orig_hs_expr ty bad_tys- | otherwise = return ()
compiler/GHC/HsToCore/Expr.hs-boot view
@@ -5,6 +5,6 @@ import GHC.Hs.Extension ( GhcTc) dsExpr :: HsExpr GhcTc -> DsM CoreExpr-dsLExpr, dsLExprNoLP :: LHsExpr GhcTc -> DsM CoreExpr+dsLExpr :: LHsExpr GhcTc -> DsM CoreExpr dsSyntaxExpr :: SyntaxExpr GhcTc -> [CoreExpr] -> DsM CoreExpr dsLocalBinds :: HsLocalBinds GhcTc -> CoreExpr -> DsM CoreExpr
compiler/GHC/HsToCore/ListComp.hs view
@@ -13,10 +13,9 @@ import GHC.Prelude -import {-# SOURCE #-} GHC.HsToCore.Expr ( dsExpr, dsLExpr, dsLExprNoLP, dsLocalBinds, dsSyntaxExpr )+import {-# SOURCE #-} GHC.HsToCore.Expr ( dsExpr, dsLExpr, dsLocalBinds, dsSyntaxExpr ) import GHC.Hs-import GHC.Tc.Errors.Types ( LevityCheckProvenance(..) ) import GHC.Hs.Syn.Type import GHC.Core import GHC.Core.Make@@ -139,8 +138,6 @@ , Var unzip_fn' , inner_list_expr' ] - dsNoLevPoly (tcFunResultTyN (length usingArgs') (exprType usingExpr')) (LevityCheckInFunUse using)- -- Build a pattern that ensures the consumer binds into the NEW binders, -- which hold lists rather than single values let pat = mkBigLHsVarPatTupId to_bndrs -- NB: no '!@@ -240,7 +237,7 @@ deBindComp pat inner_list_expr quals list deListComp (BindStmt _ pat list1 : quals) core_list2 = do -- rule A' above- core_list1 <- dsLExprNoLP list1+ core_list1 <- dsLExpr list1 deBindComp pat core_list1 quals core_list2 deListComp (ParStmt _ stmtss_w_bndrs _ _ : quals) list@@ -328,7 +325,7 @@ dfListComp c_id n_id (LastStmt _ body _ _ : quals) = assert (null quals) $- do { core_body <- dsLExprNoLP body+ do { core_body <- dsLExpr body ; return (mkApps (Var c_id) [core_body, Var n_id]) } -- Non-last: must be a guard@@ -549,7 +546,7 @@ ; let tup_n_ty' = mkBigCoreVarTupTy to_bndrs ; body <- dsMcStmts stmts_rest- ; n_tup_var' <- newSysLocalDsNoLP Many n_tup_ty'+ ; n_tup_var' <- newSysLocalDs Many n_tup_ty' ; tup_n_var' <- newSysLocalDs Many tup_n_ty' ; tup_n_expr' <- mkMcUnzipM form fmap_op n_tup_var' from_bndr_tys ; us <- newUniqueSupply
compiler/GHC/HsToCore/Match.hs view
@@ -750,7 +750,7 @@ ; locn <- getSrcSpanDs ; new_vars <- case matches of- [] -> newSysLocalsDsNoLP arg_tys+ [] -> newSysLocalsDs arg_tys (m:_) -> selectMatchVars (zipWithEqual "matchWrapper" (\a b -> (scaledMult a, unLoc b))@@ -1117,7 +1117,7 @@ -- equating different ways of writing a coercion) wrap WpHole WpHole = True wrap (WpCompose w1 w2) (WpCompose w1' w2') = wrap w1 w1' && wrap w2 w2'- wrap (WpFun w1 w2 _ _) (WpFun w1' w2' _ _) = wrap w1 w1' && wrap w2 w2'+ wrap (WpFun w1 w2 _) (WpFun w1' w2' _) = wrap w1 w1' && wrap w2 w2' wrap (WpCast co) (WpCast co') = co `eqCoercion` co' wrap (WpEvApp et1) (WpEvApp et2) = et1 `ev_term` et2 wrap (WpTyApp t) (WpTyApp t') = eqType t t'
compiler/GHC/HsToCore/Match/Constructor.hs view
@@ -245,10 +245,11 @@ ----------------- selectConMatchVars :: [Scaled Type] -> ConArgPats -> DsM [Id]-selectConMatchVars arg_tys con = case con of- (RecCon {}) -> newSysLocalsDsNoLP arg_tys- (PrefixCon _ ps) -> selectMatchVars (zipMults arg_tys ps)- (InfixCon p1 p2) -> selectMatchVars (zipMults arg_tys [p1, p2])+selectConMatchVars arg_tys con+ = case con of+ RecCon {} -> newSysLocalsDs arg_tys+ PrefixCon _ ps -> selectMatchVars (zipMults arg_tys ps)+ InfixCon p1 p2 -> selectMatchVars (zipMults arg_tys [p1, p2]) where zipMults = zipWithEqual "selectConMatchVar" (\a b -> (scaledMult a, unLoc b))
compiler/GHC/HsToCore/Monad.hs view
@@ -19,8 +19,8 @@ foldlM, foldrM, whenGOptM, unsetGOptM, unsetWOptM, xoptM, Applicative(..),(<$>), - duplicateLocalDs, newSysLocalDsNoLP, newSysLocalDs,- newSysLocalsDsNoLP, newSysLocalsDs, newUniqueId,+ duplicateLocalDs, newSysLocalDs,+ newSysLocalsDs, newUniqueId, newFailLocalDs, newPredVarDs, getSrcSpanDs, putSrcSpanDs, putSrcSpanDsA, mkPrintUnqualifiedDs,@@ -42,15 +42,11 @@ -- Warnings and errors DsWarning, diagnosticDs, errDsCoreExpr, failWithDs, failDs, discardWarningsDs,- askNoErrsDs, -- Data types DsMatchContext(..), EquationInfo(..), MatchResult (..), runMatchResult, DsWrapper, idDsWrapper, - -- Representation polymorphism- dsNoLevPoly, dsNoLevPolyExpr,- -- Trace injection pprRuntimeTrace ) where@@ -71,7 +67,7 @@ import GHC.Core.FamInstEnv import GHC.Core import GHC.Core.Make ( unitExpr )-import GHC.Core.Utils ( exprType, isExprLevPoly )+import GHC.Core.Utils ( exprType ) import GHC.Core.DataCon import GHC.Core.ConLike import GHC.Core.TyCon@@ -80,9 +76,7 @@ import GHC.IfaceToCore -import GHC.Tc.Errors.Types ( LevityCheckProvenance(..) ) import GHC.Tc.Utils.Monad-import GHC.Tc.Utils.TcMType ( checkForLevPolyX ) import GHC.Builtin.Names @@ -371,56 +365,11 @@ functions are defined with it. The difference in name-strings makes it easier to read debugging output. -Note [Representation polymorphism checking]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-According to the "Levity Polymorphism" paper (PLDI '17),-representation polymorphism is forbidden in precisely two places:-in the type of a bound term-level argument, and in the type of an argument-to a function.-Note that the paper doesn't distinguish levity polymorphism, such as- \(v::Levity). \(a::TYPE (BoxedRep v)). \(x::a). expr-from the more general representation polymorphism, as the BoxedRep-constructor of RuntimeRep didn't exist at the time.--The paper explains the restrictions more fully, but briefly:-expressions in these contexts need to be stored in registers, and it's-hard (read: impossible) to store something that's representation-polymorphic.--We cannot check for bad representation polymorphism conveniently-in the type checker, because we can't tell, a priori, which-representation metavariables will be solved.-At one point, I (Richard) thought we could check in the zonker, but it's hard-to know where precisely are the abstracted variables and the arguments. So-we check in the desugarer, the only place where we can see the Core code and-still report respectable syntax to the user. This covers the vast majority-of cases; see calls to GHC.HsToCore.Monad.dsNoLevPoly and friends.--Representation polymorphism is also prohibited in the types of binders, and the-desugarer checks for this in GHC-generated Ids. (The zonker handles-the user-writted ids in zonkIdBndr.) This is done in newSysLocalDsNoLP.-The newSysLocalDs variant is used in the vast majority of cases where-the binder is obviously not representation-polymorphic, omitting the check.-It would be nice to ASSERT that there is no representation polymorphism here,-but we can't, because of the fixM in GHC.HsToCore.Arrows. It's all OK, though:-Core Lint will catch an error here.--However, the desugarer is the wrong place for certain checks. In particular,-the desugarer can't report a sensible error message if an HsWrapper is malformed.-After all, GHC itself produced the HsWrapper. So we store some message text-in the appropriate HsWrappers (e.g. WpFun) that we can print out in the-desugarer.--There are a few more checks in places where Core is generated outside the-desugarer. For example, in datatype and class declarations, where-representation polymorphism is checked for during validity checking.-It would be nice to have one central place for all this, but that doesn't-seem possible while still reporting nice error messages.- -} -- Make a new Id with the same print name, but different type, and new unique newUniqueId :: Id -> Mult -> Type -> DsM Id-newUniqueId id = mk_local (occNameFS (nameOccName (idName id)))+newUniqueId id = mkSysLocalOrCoVarM (occNameFS (nameOccName (idName id))) duplicateLocalDs :: Id -> DsM Id duplicateLocalDs old_local@@ -431,27 +380,13 @@ newPredVarDs = mkSysLocalOrCoVarM (fsLit "ds") Many -- like newSysLocalDs, but we allow covars -newSysLocalDsNoLP, newSysLocalDs, newFailLocalDs :: Mult -> Type -> DsM Id-newSysLocalDsNoLP = mk_local (fsLit "ds")---- this variant should be used when the caller can be sure that the variable type--- is not representation-polymorphic. It is necessary when the type--- is knot-tied because of the fixM used in GHC.HsToCore.Arrows.--- See Note [Representation polymorphism checking]+newSysLocalDs, newFailLocalDs :: Mult -> Type -> DsM Id newSysLocalDs = mkSysLocalM (fsLit "ds") newFailLocalDs = mkSysLocalM (fsLit "fail")- -- the fail variable is used only in a situation where we can tell that- -- representation polymorphism is impossible. -newSysLocalsDsNoLP, newSysLocalsDs :: [Scaled Type] -> DsM [Id]-newSysLocalsDsNoLP = mapM (\(Scaled w t) -> newSysLocalDsNoLP w t)+newSysLocalsDs :: [Scaled Type] -> DsM [Id] newSysLocalsDs = mapM (\(Scaled w t) -> newSysLocalDs w t) -mk_local :: FastString -> Mult -> Type -> DsM Id-mk_local fs w ty = do { dsNoLevPoly ty LevityCheckInVarType -- could improve the msg with another- -- parameter indicating context- ; mkSysLocalOrCoVarM fs w ty }- {- We can also reach out and either set/grab location information from the @SrcSpan@ being carried around.@@ -508,36 +443,6 @@ failDs :: DsM a failDs = failM --- (askNoErrsDs m) runs m--- If m fails,--- then (askNoErrsDs m) fails--- If m succeeds with result r,--- then (askNoErrsDs m) succeeds with result (r, b),--- where b is True iff m generated no errors--- Regardless of success or failure,--- propagate any errors/warnings generated by m------ c.f. GHC.Tc.Utils.Monad.askNoErrs-askNoErrsDs :: DsM a -> DsM (a, Bool)-askNoErrsDs thing_inside- = do { errs_var <- newMutVar emptyMessages- ; env <- getGblEnv- ; mb_res <- tryM $ -- Be careful to catch exceptions- -- so that we propagate errors correctly- -- (#13642)- setGblEnv (env { ds_msgs = errs_var }) $- thing_inside-- -- Propagate errors- ; msgs <- readMutVar errs_var- ; updMutVar (ds_msgs env) (unionMessages msgs)-- -- And return- ; case mb_res of- Left _ -> failM- Right res -> do { let errs_found = errorsFound msgs- ; return (res, not errs_found) } }- mkPrintUnqualifiedDs :: DsM PrintUnqualified mkPrintUnqualifiedDs = ds_unqual <$> getGblEnv @@ -602,20 +507,6 @@ ; writeTcRef (ds_msgs env) old_msgs ; return result }---- | Fail with an error message if the type is representation-polymorphic.-dsNoLevPoly :: Type -> LevityCheckProvenance -> DsM ()--- See Note [Representation polymorphism checking]-dsNoLevPoly ty provenance =- checkForLevPolyX (\ty -> diagnosticDs . DsLevityPolyInType ty) provenance ty---- | Check an expression for representation polymorphism, failing if it is--- representation-polymorphic.-dsNoLevPolyExpr :: CoreExpr -> LevityExprProvenance -> DsM ()--- See Note [Representation polymorphism checking]-dsNoLevPolyExpr e provenance- | isExprLevPoly e = diagnosticDs (DsLevityPolyInExpr e provenance)- | otherwise = return () -- | Inject a trace message into the compiled program. Whereas -- pprTrace prints out information *while compiling*, pprRuntimeTrace
compiler/GHC/HsToCore/Pmc/Utils.hs view
@@ -1,4 +1,5 @@ +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE ScopedTypeVariables #-} -- | Utility module for the pattern-match coverage checker.@@ -87,7 +88,7 @@ exhaustiveWarningFlag LambdaExpr = Just Opt_WarnIncompleteUniPatterns exhaustiveWarningFlag PatBindRhs = Just Opt_WarnIncompleteUniPatterns exhaustiveWarningFlag PatBindGuards = Just Opt_WarnIncompletePatterns-exhaustiveWarningFlag ProcExpr = Just Opt_WarnIncompleteUniPatterns+exhaustiveWarningFlag (ArrowMatchCtxt c) = arrowMatchContextExhaustiveWarningFlag c exhaustiveWarningFlag RecUpd = Just Opt_WarnIncompletePatternsRecUpd exhaustiveWarningFlag ThPatSplice = Nothing exhaustiveWarningFlag PatSyn = Nothing@@ -95,6 +96,12 @@ -- Don't warn about incomplete patterns in list comprehensions, pattern guards -- etc. They are often *supposed* to be incomplete exhaustiveWarningFlag (StmtCtxt {}) = Nothing++arrowMatchContextExhaustiveWarningFlag :: HsArrowMatchContext -> Maybe WarningFlag+arrowMatchContextExhaustiveWarningFlag = \ case+ ProcExpr -> Just Opt_WarnIncompleteUniPatterns+ ArrowCaseAlt -> Just Opt_WarnIncompletePatterns+ KappaExpr -> Just Opt_WarnIncompleteUniPatterns -- | Check whether any part of pattern match checking is enabled for this -- 'HsMatchContext' (does not matter whether it is the redundancy check or the
compiler/GHC/HsToCore/Utils.hs view
@@ -30,7 +30,7 @@ wrapBind, wrapBinds, mkErrorAppDs, mkCoreAppDs, mkCoreAppsDs, mkCastDs,- mkFailExpr, dsWhenNoErrs,+ mkFailExpr, seqVar, @@ -132,10 +132,10 @@ selectMatchVar :: Mult -> Pat GhcTc -> DsM Id -- Postcondition: the returned Id has an Internal Name-selectMatchVar w (BangPat _ pat) = selectMatchVar w (unLoc pat)-selectMatchVar w (LazyPat _ pat) = selectMatchVar w (unLoc pat)+selectMatchVar w (BangPat _ pat) = selectMatchVar w (unLoc pat)+selectMatchVar w (LazyPat _ pat) = selectMatchVar w (unLoc pat) selectMatchVar w (ParPat _ _ pat _) = selectMatchVar w (unLoc pat)-selectMatchVar _w (VarPat _ var) = return (localiseId (unLoc var))+selectMatchVar _w (VarPat _ var) = return (localiseId (unLoc var)) -- Note [Localise pattern binders] -- -- Remark: when the pattern is a variable (or@@ -144,7 +144,7 @@ -- 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 other_pat = newSysLocalDsNoLP w (hsPatType other_pat)+selectMatchVar w other_pat = newSysLocalDs w (hsPatType other_pat) {- Note [Localise pattern binders] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@@ -739,7 +739,7 @@ | is_flat_prod_lpat pat' -- Special case (B) = do { let pat_ty = hsLPatType pat'- ; val_var <- newSysLocalDsNoLP Many pat_ty+ ; val_var <- newSysLocalDs Many pat_ty ; let mk_bind tick bndr_var -- (mk_bind sv bv) generates bv = case sv of { pat -> bv }@@ -981,69 +981,6 @@ mk_fail_msg dflags ctx pat = showPpr dflags $ text "Pattern match failure in" <+> pprHsDoFlavour ctx <+> text "at" <+> ppr (getLocA pat)--{- Note [Desugaring representation-polymorphic applications]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-To desugar a function application--> HsApp _ f e :: HsExpr GhcTc--into Core, we need to know whether the argument e is lifted or unlifted,-in order to respect the let/app invariant.- (See Note [Core let/app invariant] in GHC.Core)--This causes a problem when e is representation-polymorphic, as we aren't able-to determine whether to build a Core application--> f_desugared e_desugared--or a strict binding:--> case e_desugared of { x -> f_desugared x }--See GHC.Core.Make.mkValApp, which will call isUnliftedType, which panics-on a representation-polymorphic type.--These representation-polymorphic applications are disallowed in source Haskell,-but we might want to continue desugaring as much as possible instead of-aborting as soon as we see such a problematic function application.--When desugaring an expression which might have problems (such as disallowed-representation polymorphism as above), we check for errors first, and then:-- - if no problems were detected, desugar normally,- - if errors were found, we want to avoid desugaring, so we instead return- a runtime error Core expression which has the right type.--This is what the function dsWhenNoErrs achieves:--> dsWhenNoErrs result_ty thing_inside mk_expr--We run thing_inside to check for errors. If there are no errors, we apply-mk_expr to desugar; otherwise, we construct a runtime error at type result_ty.--Note that result_ty is only used when there is an error, and isn't inspected-otherwise; this means it's OK to pass something that can be a bit expensive-to compute.--See #12709 for an example of why this machinery is necessary.-See also #14765 and #18149 for why it is important to return an expression-that has the proper type in case of an error.--}---- | Runs the thing_inside. If there are no errors, use the provided--- function to construct a Core expression, and return it.--- Otherwise, return a runtime error, of the given type.--- This is useful for doing a bunch of representation polymorphism checks--- and then avoiding making a Core App.--- See Note [Desugaring representation-polymorphic applications]-dsWhenNoErrs :: Type -> DsM a -> (a -> CoreExpr) -> DsM CoreExpr-dsWhenNoErrs result_ty thing_inside mk_expr- = do { (result, no_errs) <- askNoErrsDs thing_inside- ; if no_errs- then return $ mk_expr result- else mkErrorAppDs rUNTIME_ERROR_ID result_ty- (text "dsWhenNoErrs found errors") } {- ********************************************************************* * *
compiler/GHC/Iface/Ext/Ast.hs view
@@ -396,8 +396,7 @@ getRealSpan (RealSrcSpan sp _) = Just sp getRealSpan _ = Nothing -grhss_span :: (Anno (GRHS (GhcPass p) (LocatedA (body (GhcPass p)))) ~ SrcSpan- , Data (HsLocalBinds (GhcPass p)))+grhss_span :: (Anno (GRHS (GhcPass p) (LocatedA (body (GhcPass p)))) ~ SrcSpan) => GRHSs (GhcPass p) (LocatedA (body (GhcPass p))) -> SrcSpan grhss_span (GRHSs _ xs bs) = foldl' combineSrcSpans (spanHsLocaLBinds bs) (map getLoc xs) @@ -589,8 +588,8 @@ instance (ToHie a) => ToHie (Maybe a) where toHie = maybe (pure []) toHie -instance ToHie (IEContext (Located ModuleName)) where- toHie (IEC c (L (RealSrcSpan span _) mname)) = do+instance ToHie (IEContext (LocatedA ModuleName)) where+ toHie (IEC c (L (SrcSpanAnn _ (RealSrcSpan span _)) mname)) = do org <- ask pure $ [Node (mkSourcedNodeInfo org $ NodeInfo S.empty [] idents) span []] where details = mempty{identInfo = S.singleton (IEThing c)}@@ -681,7 +680,7 @@ (WpLet bs) -> toHie $ EvBindContext (mkScopeA osp) (getRealSpanA osp) (L osp bs) (WpCompose a b) -> concatM $ [toHie (L osp a), toHie (L osp b)]- (WpFun a b _ _) -> concatM $+ (WpFun a b _) -> concatM $ [toHie (L osp a), toHie (L osp b)] (WpEvLam a) -> toHie $ C (EvidenceVarBind EvWrapperBind (mkScopeA osp) (getRealSpanA osp))@@ -781,8 +780,8 @@ HieRn :: HiePassEv 'Renamed HieTc :: HiePassEv 'Typechecked -class ( IsPass p- , HiePass (NoGhcTcPass p)+class ( HiePass (NoGhcTcPass p)+ , NoGhcTcPass p ~ 'Renamed , ModifyState (IdGhcP p) , Data (GRHS (GhcPass p) (LocatedA (HsExpr (GhcPass p)))) , Data (Match (GhcPass p) (LocatedA (HsExpr (GhcPass p))))@@ -800,10 +799,6 @@ , Data (HsTupArg (GhcPass p)) , Data (IPBind (GhcPass p)) , ToHie (Context (Located (IdGhcP p)))- , ToHie (RFContext (Located (AmbiguousFieldOcc (GhcPass p))))- , ToHie (RFContext (Located (FieldOcc (GhcPass p))))- , ToHie (TScoped (LHsWcType (GhcPass (NoGhcTcPass p))))- , ToHie (TScoped (LHsSigWcType (GhcPass (NoGhcTcPass p)))) , Anno (IdGhcP p) ~ SrcSpanAnnN ) => HiePass p where@@ -830,8 +825,6 @@ , Data (Match (GhcPass p) (LocatedA (body (GhcPass p)))) , Data (GRHS (GhcPass p) (LocatedA (body (GhcPass p)))) , Data (Stmt (GhcPass p) (LocatedA (body (GhcPass p))))-- , IsPass p ) instance HiePass p => ToHie (BindContext (LocatedA (HsBind (GhcPass p)))) where@@ -920,17 +913,13 @@ , AnnoBody p body , ToHie (LocatedA (body (GhcPass p))) ) => ToHie (LocatedA (Match (GhcPass p) (LocatedA (body (GhcPass p))))) where- toHie (L span m ) = concatM $ node : case m of+ toHie (L span m ) = concatM $ makeNodeA m span : case m of Match{m_ctxt=mctx, m_pats = pats, m_grhss = grhss } -> [ toHie mctx , let rhsScope = mkScope $ grhss_span grhss in toHie $ patScopes Nothing rhsScope NoScope pats , toHie grhss ]- where- node = case hiePass @p of- HieTc -> makeNodeA m span- HieRn -> makeNodeA m span instance HiePass p => ToHie (HsMatchContext (GhcPass p)) where toHie (FunRhs{mc_fun=name}) = toHie $ C MatchBind name'@@ -1035,8 +1024,8 @@ ] ExpansionPat _ p -> [ toHie $ PS rsp scope pscope (L ospan p) ] where- contextify :: a ~ LPat (GhcPass p) => HsConDetails (HsPatSigType (NoGhcTc (GhcPass p))) a (HsRecFields (GhcPass p) a)- -> HsConDetails (TScoped (HsPatSigType (NoGhcTc (GhcPass p)))) (PScoped a) (RContext (HsRecFields (GhcPass p) (PScoped a)))+ contextify :: a ~ LPat (GhcPass p) => HsConDetails (HsPatSigType GhcRn) a (HsRecFields (GhcPass p) a)+ -> HsConDetails (TScoped (HsPatSigType GhcRn)) (PScoped a) (RContext (HsRecFields (GhcPass p) (PScoped a))) contextify (PrefixCon tyargs args) = PrefixCon (tScopes scope argscope tyargs) (patScopes rsp scope pscope args) where argscope = foldr combineScopes NoScope $ map mkLScopeA args contextify (InfixCon a b) = InfixCon a' b'@@ -1071,15 +1060,11 @@ , HiePass p , AnnoBody p body ) => ToHie (Located (GRHS (GhcPass p) (LocatedA (body (GhcPass p))))) where- toHie (L span g) = concatM $ node : case g of+ toHie (L span g) = concatM $ makeNode g span : case g of GRHS _ guards body -> [ toHie $ listScopes (mkLScopeA body) guards , toHie body ]- where- node = case hiePass @p of- HieRn -> makeNode g span- HieTc -> makeNode g span instance HiePass p => ToHie (LocatedA (HsExpr (GhcPass p))) where toHie e@(L mspan oexpr) = concatM $ getTypeNode e : case oexpr of@@ -1207,7 +1192,7 @@ HsGetField {} -> [] HsProjection {} -> [] XExpr x- | GhcTc <- ghcPass @p+ | HieTc <- hiePass @p -> case x of WrapExpr (HsWrap w a) -> [ toHie $ L mspan a@@ -1349,34 +1334,23 @@ , toHie expr ] -instance ToHie (RFContext (Located (FieldOcc GhcRn))) where- toHie (RFC c rhs (L nspan f)) = concatM $ case f of- FieldOcc name _ ->- [ toHie $ C (RecField c rhs) (L nspan name)- ]--instance ToHie (RFContext (Located (FieldOcc GhcTc))) where+instance HiePass p => ToHie (RFContext (Located (FieldOcc (GhcPass p)))) where toHie (RFC c rhs (L nspan f)) = concatM $ case f of- FieldOcc var _ ->- [ toHie $ C (RecField c rhs) (L nspan var)- ]--instance ToHie (RFContext (Located (AmbiguousFieldOcc GhcRn))) where- toHie (RFC c rhs (L nspan afo)) = concatM $ case afo of- Unambiguous name _ ->- [ toHie $ C (RecField c rhs) $ L nspan name- ]- Ambiguous _name _ ->- [ ]+ FieldOcc fld _ ->+ case hiePass @p of+ HieRn -> [toHie $ C (RecField c rhs) (L nspan fld)]+ HieTc -> [toHie $ C (RecField c rhs) (L nspan fld)] -instance ToHie (RFContext (Located (AmbiguousFieldOcc GhcTc))) where+instance HiePass p => ToHie (RFContext (Located (AmbiguousFieldOcc (GhcPass p)))) where toHie (RFC c rhs (L nspan afo)) = concatM $ case afo of- Unambiguous var _ ->- [ toHie $ C (RecField c rhs) (L nspan var)- ]- Ambiguous var _ ->- [ toHie $ C (RecField c rhs) (L nspan var)- ]+ Unambiguous fld _ ->+ case hiePass @p of+ HieRn -> [toHie $ C (RecField c rhs) $ L nspan fld]+ HieTc -> [toHie $ C (RecField c rhs) $ L nspan fld]+ Ambiguous fld _ ->+ case hiePass @p of+ HieRn -> []+ HieTc -> [ toHie $ C (RecField c rhs) (L nspan fld) ] instance HiePass p => ToHie (RScoped (ApplicativeArg (GhcPass p))) where toHie (RS sc (ApplicativeArgOne _ pat expr _)) = concatM@@ -1914,12 +1888,11 @@ ] HsSpliced _ _ _ -> []- XSplice x -> case ghcPass @p of+ XSplice x -> case hiePass @p of #if __GLASGOW_HASKELL__ < 811- GhcPs -> noExtCon x- GhcRn -> noExtCon x+ HieRn -> noExtCon x #endif- GhcTc -> case x of+ HieTc -> case x of HsSplicedT _ -> [] instance ToHie (LocatedA (RoleAnnotDecl GhcRn)) where
compiler/GHC/Iface/Ext/Types.hs view
@@ -155,6 +155,7 @@ -- | Roughly isomorphic to the original core 'Type'. newtype HieTypeFix = Roll (HieType (HieTypeFix))+ deriving Eq instance Binary (HieType TypeIndex) where put_ bh (HTyVarTy n) = do
compiler/GHC/Iface/Load.hs view
@@ -10,6 +10,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE ViewPatterns #-} -- | Loading interface files module GHC.Iface.Load (@@ -47,7 +48,6 @@ import GHC.Driver.Env import GHC.Driver.Errors.Types import GHC.Driver.Session-import GHC.Driver.Backend import GHC.Driver.Hooks import GHC.Driver.Plugins @@ -98,6 +98,7 @@ import GHC.Types.Unique.DSet import GHC.Types.SrcLoc import GHC.Types.TyThing+import GHC.Types.PkgQual import GHC.Unit.External import GHC.Unit.Module@@ -111,7 +112,6 @@ import GHC.Unit.Env ( ue_hpt ) import GHC.Data.Maybe-import GHC.Data.FastString import Control.Monad import Data.Map ( toList )@@ -295,7 +295,7 @@ loadSrcInterface :: SDoc -> ModuleName -> IsBootInterface -- {-# SOURCE #-} ?- -> Maybe FastString -- "package", if any+ -> PkgQual -- "package", if any -> RnM ModIface loadSrcInterface doc mod want_boot maybe_pkg@@ -308,7 +308,7 @@ loadSrcInterface_maybe :: SDoc -> ModuleName -> IsBootInterface -- {-# SOURCE #-} ?- -> Maybe FastString -- "package", if any+ -> PkgQual -- "package", if any -> RnM (MaybeErr SDoc ModIface) loadSrcInterface_maybe doc mod want_boot maybe_pkg@@ -629,37 +629,51 @@ home-package modules however, so it's safe for the HPT to be empty. -} +-- Note [GHC Heap Invariants] dontLeakTheHPT :: IfL a -> IfL a dontLeakTheHPT thing_inside = do+ env <- getTopEnv let+ inOneShot =+ isOneShot (ghcMode (hsc_dflags env))+ cleanGblEnv gbl_env+ | inOneShot = gbl_env+ | otherwise = gbl_env { if_rec_types = emptyKnotVars } cleanTopEnv hsc_env =+ let+ !maybe_type_vars | inOneShot = Just (hsc_type_env_vars env)+ | otherwise = Nothing -- wrinkle: when we're typechecking in --backpack mode, the -- instantiation of a signature might reside in the HPT, so -- this case breaks the assumption that EPS interfaces only- -- refer to other EPS interfaces. We can detect when we're in- -- typechecking-only mode by using backend==NoBackend, and- -- in that case we don't empty the HPT. (admittedly this is- -- a bit of a hack, better suggestions welcome). A number of- -- tests in testsuite/tests/backpack break without this+ -- refer to other EPS interfaces.+ -- As a temporary (MP Oct 2021 #20509) we only keep the HPT if it+ -- contains any hole modules.+ -- Quite a few tests in testsuite/tests/backpack break without this -- tweak. old_unit_env = hsc_unit_env hsc_env+ keepFor20509 hmi+ | isHoleModule (mi_semantic_module (hm_iface hmi)) = True+ | otherwise = False !unit_env- | NoBackend <- backend (hsc_dflags hsc_env) = old_unit_env- | otherwise- = old_unit_env- { ue_hpt = emptyHomePackageTable+ { ue_hpt = if anyHpt keepFor20509 (ue_hpt old_unit_env) then ue_hpt old_unit_env+ else emptyHomePackageTable } in hsc_env { hsc_targets = panic "cleanTopEnv: hsc_targets" , hsc_mod_graph = panic "cleanTopEnv: hsc_mod_graph" , hsc_IC = panic "cleanTopEnv: hsc_IC"+ , hsc_type_env_vars = case maybe_type_vars of+ Just vars -> vars+ Nothing -> panic "cleanTopEnv: hsc_type_env_vars" , hsc_unit_env = unit_env } - updTopEnv cleanTopEnv $ do+ updTopEnv cleanTopEnv $ updGblEnv cleanGblEnv $ do !_ <- getTopEnv -- force the updTopEnv+ !_ <- getGblEnv thing_inside @@ -887,23 +901,24 @@ -- Look for the file mb_found <- liftIO (findExactModule fc fopts unit_state home_unit mod) case mb_found of- InstalledFound loc mod -> do- -- Found file, so read it- let file_path = addBootSuffix_maybe hi_boot_file (ml_hi_file loc)+ InstalledFound (addBootSuffixLocn_maybe hi_boot_file -> loc) mod -> do -- See Note [Home module load error] if isHomeInstalledModule home_unit mod && not (isOneShot (ghcMode dflags)) then return (Failed (homeModError mod loc)) else do- r <- read_file logger name_cache unit_state dflags wanted_mod file_path+ r <- read_file logger name_cache unit_state dflags wanted_mod (ml_hi_file loc) case r of Failed _- -> return ()- Succeeded (iface,fp)- -> load_dynamic_too_maybe logger name_cache unit_state- dflags wanted_mod- hi_boot_file iface fp- return r+ -> return r+ Succeeded (iface,_fp)+ -> do+ r2 <- load_dynamic_too_maybe logger name_cache unit_state+ (setDynamicNow dflags) wanted_mod+ iface loc+ case r2 of+ Failed sdoc -> return (Failed sdoc)+ Succeeded {} -> return r err -> do trace_if logger (text "...not found") return $ Failed $ cannotFindInterface@@ -915,30 +930,32 @@ err -- | Check if we need to try the dynamic interface for -dynamic-too-load_dynamic_too_maybe :: Logger -> NameCache -> UnitState -> DynFlags -> Module -> IsBootInterface -> ModIface -> FilePath -> IO ()-load_dynamic_too_maybe logger name_cache unit_state dflags wanted_mod is_boot iface file_path+load_dynamic_too_maybe :: Logger -> NameCache -> UnitState -> DynFlags -> Module -> ModIface -> ModLocation -> IO (MaybeErr SDoc ())+load_dynamic_too_maybe logger name_cache unit_state dflags wanted_mod iface loc -- Indefinite interfaces are ALWAYS non-dynamic.- | not (moduleIsDefinite (mi_module iface)) = return ()- | otherwise = dynamicTooState dflags >>= \case- DT_Dont -> return ()- DT_Failed -> return ()- DT_Dyn -> load_dynamic_too logger name_cache unit_state dflags wanted_mod is_boot iface file_path- DT_OK -> load_dynamic_too logger name_cache unit_state (setDynamicNow dflags) wanted_mod is_boot iface file_path+ | not (moduleIsDefinite (mi_module iface)) = return (Succeeded ())+ | gopt Opt_BuildDynamicToo dflags = load_dynamic_too logger name_cache unit_state dflags wanted_mod iface loc+ | otherwise = return (Succeeded ()) -load_dynamic_too :: Logger -> NameCache -> UnitState -> DynFlags -> Module -> IsBootInterface -> ModIface -> FilePath -> IO ()-load_dynamic_too logger name_cache unit_state dflags wanted_mod is_boot iface file_path = do- let dynFilePath = addBootSuffix_maybe is_boot- $ replaceExtension file_path (hiSuf dflags)- read_file logger name_cache unit_state dflags wanted_mod dynFilePath >>= \case+load_dynamic_too :: Logger -> NameCache -> UnitState -> DynFlags -> Module -> ModIface -> ModLocation -> IO (MaybeErr SDoc ())+load_dynamic_too logger name_cache unit_state dflags wanted_mod iface loc = do+ read_file logger name_cache unit_state dflags wanted_mod (ml_dyn_hi_file loc) >>= \case Succeeded (dynIface, _) | mi_mod_hash (mi_final_exts iface) == mi_mod_hash (mi_final_exts dynIface)- -> return ()+ -> return (Succeeded ()) | otherwise ->- do trace_if logger (text "Dynamic hash doesn't match")- setDynamicTooFailed dflags+ do return $ (Failed $ dynamicHashMismatchError wanted_mod loc) Failed err ->- do trace_if logger (text "Failed to load dynamic interface file:" $$ err)- setDynamicTooFailed dflags+ do return $ (Failed $ ((text "Failed to load dynamic interface file for" <+> ppr wanted_mod <> colon) $$ err))+++dynamicHashMismatchError :: Module -> ModLocation -> SDoc+dynamicHashMismatchError wanted_mod loc =+ vcat [ text "Dynamic hash doesn't match for" <+> quotes (ppr wanted_mod)+ , text "Normal interface file from" <+> text (ml_hi_file loc)+ , text "Dynamic interface file from" <+> text (ml_dyn_hi_file loc)+ , text "You probably need to recompile" <+> quotes (ppr wanted_mod) ]+ read_file :: Logger -> NameCache -> UnitState -> DynFlags -> Module -> FilePath -> IO (MaybeErr SDoc (ModIface, FilePath)) read_file logger name_cache unit_state dflags wanted_mod file_path = do
compiler/GHC/Iface/Recomp.hs view
@@ -152,6 +152,8 @@ | MissingBytecode | MissingObjectFile | MissingDynObjectFile+ | MissingDynHiFile+ | MismatchedDynHiFile deriving (Eq) instance Outputable RecompReason where@@ -180,6 +182,8 @@ MissingBytecode -> text "Missing bytecode" MissingObjectFile -> text "Missing object file" MissingDynObjectFile -> text "Missing dynamic object file"+ MissingDynHiFile -> text "Missing dynamic interface file"+ MismatchedDynHiFile -> text "Mismatched dynamic interface file" recompileRequired :: RecompileRequired -> Bool recompileRequired UpToDate = False@@ -227,12 +231,11 @@ trace_if logger (text "We already have the old interface for" <+> ppr (ms_mod mod_summary)) return maybe_iface- Nothing -> loadIface+ Nothing -> loadIface dflags (msHiFilePath mod_summary) - loadIface = do- let iface_path = msHiFilePath mod_summary+ loadIface read_dflags iface_path = do let ncu = hsc_NC hsc_env- read_result <- readIface dflags ncu (ms_mod mod_summary) iface_path+ read_result <- readIface read_dflags ncu (ms_mod mod_summary) iface_path case read_result of Failed err -> do trace_if logger (text "FYI: cannot read old interface file:" $$ nest 4 err)@@ -241,7 +244,24 @@ Succeeded iface -> do trace_if logger (text "Read the interface file" <+> text iface_path) return $ Just iface+ check_dyn_hi :: ModIface+ -> IfG (RecompileRequired, Maybe a)+ -> IfG (RecompileRequired, Maybe a)+ check_dyn_hi normal_iface recomp_check | gopt Opt_BuildDynamicToo dflags = do+ res <- recomp_check+ case fst res of+ UpToDate -> do+ maybe_dyn_iface <- liftIO $ loadIface (setDynamicNow dflags) (msDynHiFilePath mod_summary)+ case maybe_dyn_iface of+ Nothing -> return (RecompBecause MissingDynHiFile, Nothing)+ Just dyn_iface | mi_iface_hash (mi_final_exts dyn_iface)+ /= mi_iface_hash (mi_final_exts normal_iface)+ -> return (RecompBecause MismatchedDynHiFile, Nothing)+ Just {} -> return res+ _ -> return res+ check_dyn_hi _ recomp_check = recomp_check + src_changed | gopt Opt_ForceRecomp dflags = True | otherwise = False@@ -273,7 +293,7 @@ -- should check versions because some packages -- might have changed or gone away. Just iface ->- checkVersions hsc_env mod_summary iface+ check_dyn_hi iface $ checkVersions hsc_env mod_summary iface -- | Check if a module is still the same 'version'. --@@ -531,8 +551,9 @@ home_unit = hsc_home_unit hsc_env units = hsc_units hsc_env prev_dep_mods = map gwib_mod $ Set.toAscList $ dep_direct_mods (mi_deps iface)- prev_dep_pkgs = Set.toAscList (dep_direct_pkgs (mi_deps iface))- bkpk_units = map (("Signature",) . indefUnit . instUnitInstanceOf . moduleUnit) (requirementMerges units (moduleName (mi_module 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))) implicit_deps = map ("Implicit",) (implicitPackageDeps dflags) @@ -1540,10 +1561,17 @@ -- Kind of a heinous hack. initIfaceLoad hsc_env . withException ctx $ withoutDynamicNow- -- For some unknown reason, we need to reset the- -- dynamicNow bit, otherwise only dynamic- -- interfaces are looked up and some tests fail- -- (e.g. T16219).+ -- If you try and load interfaces when dynamic-too+ -- enabled then it attempts to load the dyn_hi and hi+ -- interface files. Backpack doesn't really care about+ -- dynamic object files as it isn't doing any code+ -- generation so -dynamic-too is turned off.+ -- Some tests fail without doing this (such as T16219),+ -- but they fail because dyn_hi files are not found for+ -- one of the dependencies (because they are deliberately turned off)+ -- Why is this check turned off here? That is unclear but+ -- just one of the many horrible hacks in the backpack+ -- implementation. $ loadInterface (text "lookupVers2") mod ImportBySystem return $ snd (mi_hash_fn (mi_final_exts iface) occ `orElse` pprPanic "lookupVers1" (ppr mod <+> ppr occ))
compiler/GHC/IfaceToCore.hs view
@@ -238,7 +238,7 @@ -- | Returns true if an 'IfaceDecl' is for @data T@ (an abstract data type) isAbstractIfaceDecl :: IfaceDecl -> Bool-isAbstractIfaceDecl IfaceData{ ifCons = IfAbstractTyCon } = True+isAbstractIfaceDecl IfaceData{ ifCons = IfAbstractTyCon {} } = True isAbstractIfaceDecl IfaceClass{ ifBody = IfAbstractClass } = True isAbstractIfaceDecl IfaceFamily{ ifFamFlav = IfaceAbstractClosedSynFamilyTyCon } = True isAbstractIfaceDecl _ = False@@ -1035,11 +1035,17 @@ tcIfaceDataCons :: Name -> TyCon -> [TyConBinder] -> IfaceConDecls -> IfL AlgTyConRhs tcIfaceDataCons tycon_name tycon tc_tybinders if_cons = case if_cons of- IfAbstractTyCon -> return AbstractTyCon- IfDataTyCon cons -> do { data_cons <- mapM tc_con_decl cons- ; return (mkDataTyConRhs data_cons) }- IfNewTyCon con -> do { data_con <- tc_con_decl con- ; mkNewTyConRhs tycon_name tycon data_con }+ IfAbstractTyCon+ -> return AbstractTyCon+ IfDataTyCon cons+ -> do { data_cons <- mapM tc_con_decl cons+ ; return $+ mkLevPolyDataTyConRhs+ (isFixedRuntimeRepKind $ tyConResKind tycon)+ data_cons }+ IfNewTyCon con+ -> do { data_con <- tc_con_decl con+ ; mkNewTyConRhs tycon_name tycon data_con } where univ_tvs :: [TyVar] univ_tvs = binderVars tc_tybinders@@ -1661,7 +1667,7 @@ tcPrag info (HsDmdSig str) = return (info `setDmdSigInfo` str) tcPrag info (HsCprSig cpr) = return (info `setCprSigInfo` cpr) tcPrag info (HsInline prag) = return (info `setInlinePragInfo` prag)- tcPrag info HsLevity = return (info `setNeverLevPoly` ty)+ tcPrag info HsLevity = return (info `setNeverRepPoly` ty) tcPrag info (HsLFInfo lf_info) = do lf_info <- tcLFInfo lf_info return (info `setLFInfo` lf_info)@@ -1909,13 +1915,15 @@ tcIfaceCoAxiomRule :: IfLclName -> IfL CoAxiomRule--- Unlike CoAxioms, which arise form user 'type instance' declarations,--- there are a fixed set of CoAxiomRules,--- currently enumerated in typeNatCoAxiomRules+-- Unlike CoAxioms, which arise from user 'type instance' declarations,+-- there are a fixed set of CoAxiomRules:+-- - axioms for type-level literals (Nat and Symbol),+-- enumerated in typeNatCoAxiomRules tcIfaceCoAxiomRule n- = case lookupUFM typeNatCoAxiomRules n of- Just ax -> return ax- _ -> pprPanic "tcIfaceCoAxiomRule" (ppr n)+ | Just ax <- lookupUFM typeNatCoAxiomRules n+ = return ax+ | otherwise+ = pprPanic "tcIfaceCoAxiomRule" (ppr n) tcIfaceDataCon :: Name -> IfL DataCon tcIfaceDataCon name = do { thing <- tcIfaceGlobal name
compiler/GHC/Linker/Dynamic.hs view
@@ -44,7 +44,7 @@ = dflags0 verbFlags = getVerbFlags dflags- o_file = outputFile dflags+ o_file = outputFile_ dflags pkgs_with_rts <- mayThrowUnitErr (preloadUnitsInfo' unit_env dep_packages)
compiler/GHC/Linker/Loader.hs view
@@ -615,7 +615,7 @@ -- Only if we are compiling with the same ways as GHC is built -- with, can we dynamically load those object files. (see #3604) - | objectSuf dflags == normalObjectSuffix && not (null targetFullWays)+ | objectSuf_ dflags == normalObjectSuffix && not (null targetFullWays) = failNonStd dflags srcspan | otherwise = return (Just (hostWayTag ++ "o"))@@ -628,28 +628,42 @@ normalObjectSuffix :: String normalObjectSuffix = phaseInputExt StopLn +data Way' = Normal | Prof | Dyn+ failNonStd :: DynFlags -> SrcSpan -> IO (Maybe FilePath) failNonStd dflags srcspan = dieWith dflags srcspan $- text "Cannot load" <+> compWay <+>- text "objects when GHC is built" <+> ghciWay $$+ text "Cannot load" <+> pprWay' compWay <+>+ text "objects when GHC is built" <+> pprWay' ghciWay $$ text "To fix this, either:" $$ text " (1) Use -fexternal-interpreter, or" $$- text " (2) Build the program twice: once" <+>- ghciWay <> text ", and then" $$- text " with" <+> compWay <+>- text "using -osuf to set a different object file suffix."+ buildTwiceMsg where compWay- | ways dflags `hasWay` WayDyn = text "-dynamic"- | ways dflags `hasWay` WayProf = text "-prof"- | otherwise = text "normal"+ | ways dflags `hasWay` WayDyn = Dyn+ | ways dflags `hasWay` WayProf = Prof+ | otherwise = Normal ghciWay- | hostIsDynamic = text "with -dynamic"- | hostIsProfiled = text "with -prof"- | otherwise = text "the normal way"+ | hostIsDynamic = Dyn+ | hostIsProfiled = Prof+ | otherwise = Normal+ buildTwiceMsg = case (ghciWay, compWay) of+ (Normal, Dyn) -> dynamicTooMsg+ (Dyn, Normal) -> dynamicTooMsg+ _ ->+ text " (2) Build the program twice: once" <+>+ pprWay' ghciWay <> text ", and then" $$+ text " " <> pprWay' compWay <+>+ text "using -osuf to set a different object file suffix."+ dynamicTooMsg = text " (2) Use -dynamic-too," <+>+ text "and use -osuf and -dynosuf to set object file suffixes as needed."+ pprWay' :: Way' -> SDoc+ pprWay' way = text $ case way of+ Normal -> "the normal way"+ Prof -> "with -prof"+ Dyn -> "with -dynamic" getLinkDeps :: HscEnv -> HomePackageTable -> LoaderState- -> Maybe FilePath -- replace object suffices?+ -> Maybe FilePath -- replace object suffixes? -> SrcSpan -- for error messages -> [Module] -- If you need these -> IO ([Linkable], [Linkable], [UnitId]) -- ... then link these first
compiler/GHC/Linker/Static.hs view
@@ -73,7 +73,7 @@ unit_state = ue_units unit_env toolSettings' = toolSettings dflags verbFlags = getVerbFlags dflags- output_fn = exeFileName platform staticLink (outputFile dflags)+ output_fn = exeFileName platform staticLink (outputFile_ dflags) -- get the full list of packages to link with, by combining the -- explicit packages with the auto packages and all of their@@ -277,7 +277,7 @@ 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)+ output_fn = exeFileName platform True (outputFile_ dflags) full_output_fn <- if isAbsolute output_fn then return output_fn
compiler/GHC/Plugins.hs view
@@ -15,6 +15,7 @@ , module GHC.Types.Var , module GHC.Types.Id , module GHC.Types.Id.Info+ , module GHC.Types.PkgQual , module GHC.Core.Opt.Monad , module GHC.Core , module GHC.Types.Literal@@ -29,6 +30,7 @@ , module GHC.Driver.Ppr , module GHC.Unit.State , module GHC.Unit.Module+ , module GHC.Unit.Home , module GHC.Core.Type , module GHC.Core.TyCon , module GHC.Core.Coercion@@ -66,6 +68,7 @@ -- Variable naming import GHC.Types.TyThing+import GHC.Types.PkgQual import GHC.Types.SourceError import GHC.Types.Name.Reader import GHC.Types.Name.Occurrence hiding ( varName {- conflicts with Var.varName -} )@@ -92,6 +95,7 @@ import GHC.Driver.Session import GHC.Unit.State +import GHC.Unit.Home import GHC.Unit.Module import GHC.Unit.Module.ModGuts import GHC.Unit.Module.ModSummary
compiler/GHC/Rename/Bind.hs view
@@ -1220,13 +1220,16 @@ emptyCaseErr :: HsMatchContext GhcRn -> TcRnMessage emptyCaseErr ctxt = TcRnUnknownMessage $ mkPlainError noHints $- hang (text "Empty list of alternatives in" <+> pp_ctxt)+ hang (text "Empty list of alternatives in" <+> pp_ctxt ctxt) 2 (text "Use EmptyCase to allow this") where- pp_ctxt = case ctxt of- CaseAlt -> text "case expression"- LambdaExpr -> text "\\case expression"- _ -> text "(unexpected)" <+> pprMatchContextNoun ctxt+ pp_ctxt :: HsMatchContext GhcRn -> SDoc+ pp_ctxt c = case c of+ CaseAlt -> text "case expression"+ LambdaExpr -> text "\\case expression"+ ArrowMatchCtxt ArrowCaseAlt -> text "case expression"+ ArrowMatchCtxt KappaExpr -> text "kappa abstraction"+ _ -> text "(unexpected)" <+> pprMatchContextNoun c {- ************************************************************************
compiler/GHC/Rename/Env.hs view
@@ -102,6 +102,8 @@ import Control.Arrow ( first ) import Data.Function import GHC.Types.FieldLabel+import GHC.Data.Bag+import GHC.Types.PkgQual {- *********************************************************@@ -1568,7 +1570,7 @@ warnIfDeprecated :: GlobalRdrElt -> RnM () warnIfDeprecated gre@(GRE { gre_imp = iss })- | (imp_spec : _) <- iss+ | Just imp_spec <- headMaybe iss = do { dflags <- getDynFlags ; this_mod <- getModule ; when (wopt Opt_WarnWarningsDeprecations dflags &&@@ -1689,7 +1691,7 @@ -- -fimplicit-import-qualified is used with a module that exports the same -- field name multiple times (see -- Note [DuplicateRecordFields and -fimplicit-import-qualified]).- toGRE gname = GRE { gre_name = gname, gre_par = NoParent, gre_lcl = False, gre_imp = [is] }+ toGRE gname = GRE { gre_name = gname, gre_par = NoParent, gre_lcl = False, gre_imp = unitBag is } is = ImpSpec { is_decl = ImpDeclSpec { is_mod = mod, is_as = mod, is_qual = True, is_dloc = noSrcSpan } , is_item = ImpAll } -- If -fimplicit-import-qualified succeeded, the name must be qualified.@@ -1713,7 +1715,7 @@ , is_ghci , gopt Opt_ImplicitImportQualified dflags -- Enables this GHCi behaviour , not (safeDirectImpsReq dflags) -- See Note [Safe Haskell and GHCi]- = do { res <- loadSrcInterface_maybe doc mod NotBoot Nothing+ = do { res <- loadSrcInterface_maybe doc mod NotBoot NoPkgQual ; case res of Succeeded iface -> return [ gname
compiler/GHC/Rename/Expr.hs view
@@ -55,6 +55,7 @@ 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@@ -553,7 +554,7 @@ rnExpr (HsProc x pat body) = newArrowScope $- rnPat ProcExpr pat $ \ pat' -> do+ rnPat (ArrowMatchCtxt ProcExpr) pat $ \ pat' -> do { (body',fvBody) <- rnCmdTop body ; return (HsProc x pat' body', fvBody) } @@ -798,7 +799,7 @@ ; return (HsCmdApp x fun' arg', fvFun `plusFV` fvArg) } rnCmd (HsCmdLam _ matches)- = do { (matches', fvMatch) <- rnMatchGroup LambdaExpr rnLCmd matches+ = do { (matches', fvMatch) <- rnMatchGroup (ArrowMatchCtxt KappaExpr) rnLCmd matches ; return (HsCmdLam noExtField matches', fvMatch) } rnCmd (HsCmdPar x lpar e rpar)@@ -807,12 +808,12 @@ rnCmd (HsCmdCase _ expr matches) = do { (new_expr, e_fvs) <- rnLExpr expr- ; (new_matches, ms_fvs) <- rnMatchGroup CaseAlt rnLCmd matches+ ; (new_matches, ms_fvs) <- rnMatchGroup (ArrowMatchCtxt ArrowCaseAlt) rnLCmd matches ; return (HsCmdCase noExtField new_expr new_matches , e_fvs `plusFV` ms_fvs) } rnCmd (HsCmdLamCase x matches)- = do { (new_matches, ms_fvs) <- rnMatchGroup CaseAlt rnLCmd matches+ = do { (new_matches, ms_fvs) <- rnMatchGroup (ArrowMatchCtxt ArrowCaseAlt) rnLCmd matches ; return (HsCmdLamCase x new_matches, ms_fvs) } rnCmd (HsCmdIf _ _ p b1 b2)@@ -2361,6 +2362,8 @@ text "Empty statement group in parallel comprehension" emptyErr (TransStmtCtxt {}) = TcRnUnknownMessage $ mkPlainError noHints $ text "Empty statement group preceding 'group' or 'then'"+emptyErr ctxt@(HsDoStmt _) = TcRnUnknownMessage $ mkPlainError [suggestExtension LangExt.NondecreasingIndentation] $+ text "Empty" <+> pprStmtContext ctxt emptyErr ctxt = TcRnUnknownMessage $ mkPlainError noHints $ text "Empty" <+> pprStmtContext ctxt
compiler/GHC/Rename/Names.hs view
@@ -9,6 +9,7 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE LambdaCase #-} {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} {-# OPTIONS_GHC -Wno-incomplete-record-updates #-}@@ -25,6 +26,7 @@ findImportUsage, getMinimalImports, printMinimalImports,+ renamePkgQual, renameRawPkgQual, ImportDeclUsage ) where @@ -73,12 +75,14 @@ import GHC.Types.HpcInfo import GHC.Types.Unique.FM import GHC.Types.Error+import GHC.Types.PkgQual import GHC.Unit import GHC.Unit.Module.Warnings import GHC.Unit.Module.ModIface import GHC.Unit.Module.Imported import GHC.Unit.Module.Deps+import GHC.Unit.Env import GHC.Data.Maybe import GHC.Data.FastString@@ -95,6 +99,7 @@ import System.FilePath ((</>)) import System.IO+import GHC.Data.Bag {- ************************************************************************@@ -303,13 +308,15 @@ -> RnM (LImportDecl GhcRn, GlobalRdrEnv, ImportAvails, AnyHpcUsage) rnImportDecl this_mod (L loc decl@(ImportDecl { ideclName = loc_imp_mod_name- , ideclPkgQual = mb_pkg+ , ideclPkgQual = raw_pkg_qual , ideclSource = want_boot, ideclSafe = mod_safe , ideclQualified = qual_style, ideclImplicit = implicit , ideclAs = as_mod, ideclHiding = imp_details }), import_reason) = setSrcSpanA loc $ do - when (isJust mb_pkg) $ do+ case raw_pkg_qual of+ NoRawPkgQual -> pure ()+ RawPkgQual _ -> do pkg_imports <- xoptM LangExt.PackageImports when (not pkg_imports) $ addErr packageImportErr @@ -320,6 +327,9 @@ let imp_mod_name = unLoc loc_imp_mod_name doc = ppr imp_mod_name <+> import_reason + unit_env <- hsc_unit_env <$> getTopEnv+ let pkg_qual = renameRawPkgQual unit_env raw_pkg_qual+ -- Check for self-import, which confuses the typechecker (#9032) -- ghc --make rejects self-import cycles already, but batch-mode may not -- at least not until GHC.IfaceToCore.tcHiBootIface, which is too late to avoid@@ -333,13 +343,13 @@ -- extend Provenance to support a local definition in a qualified location. -- For now, we don't support it, but see #10336 when (imp_mod_name == moduleName this_mod &&- (case mb_pkg of -- If we have import "<pkg>" M, then we should- -- check that "<pkg>" is "this" (which is magic)- -- or the name of this_mod's package. Yurgh!- -- c.f. GHC.findModule, and #9997- Nothing -> True- Just (StringLiteral _ pkg_fs _) -> pkg_fs == fsLit "this" ||- fsToUnit pkg_fs == moduleUnit this_mod))+ (case pkg_qual of -- If we have import "<pkg>" M, then we should+ -- check that "<pkg>" is "this" (which is magic)+ -- or the name of this_mod's package. Yurgh!+ -- c.f. GHC.findModule, and #9997+ NoPkgQual -> True+ ThisPkg _ -> True+ OtherPkg _ -> False)) (addErr $ TcRnUnknownMessage $ mkPlainError noHints $ (text "A module cannot import itself:" <+> ppr imp_mod_name)) @@ -357,7 +367,7 @@ addDiagnostic msg - iface <- loadSrcInterface doc imp_mod_name want_boot (fmap sl_fs mb_pkg)+ iface <- loadSrcInterface doc imp_mod_name want_boot pkg_qual -- Compiler sanity check: if the import didn't say -- {-# SOURCE #-} we should not get a hi-boot file@@ -426,13 +436,45 @@ -- Complain about -Wcompat-unqualified-imports violations. warnUnqualifiedImport decl iface - let new_imp_decl = L loc (decl { ideclExt = noExtField, ideclSafe = mod_safe'- , ideclHiding = new_imp_details- , ideclName = ideclName decl- , ideclAs = ideclAs decl })+ let new_imp_decl = ImportDecl+ { ideclExt = noExtField+ , ideclSourceSrc = ideclSourceSrc decl+ , ideclName = ideclName decl+ , ideclPkgQual = pkg_qual+ , ideclSource = ideclSource decl+ , ideclSafe = mod_safe'+ , ideclQualified = ideclQualified decl+ , ideclImplicit = ideclImplicit decl+ , ideclAs = ideclAs decl+ , ideclHiding = new_imp_details+ } - return (new_imp_decl, gbl_env, imports, mi_hpc iface)+ return (L loc new_imp_decl, gbl_env, imports, mi_hpc iface) ++-- | Rename raw package imports+renameRawPkgQual :: UnitEnv -> RawPkgQual -> PkgQual+renameRawPkgQual unit_env = \case+ NoRawPkgQual -> NoPkgQual+ RawPkgQual p -> renamePkgQual unit_env (Just (sl_fs p))++-- | Rename raw package imports+renamePkgQual :: UnitEnv -> Maybe FastString -> PkgQual+renamePkgQual unit_env mb_pkg = case mb_pkg of+ Nothing -> NoPkgQual+ Just pkg_fs+ | Just uid <- homeUnitId <$> ue_home_unit unit_env+ , pkg_fs == fsLit "this" || pkg_fs == unitFS uid+ -> ThisPkg uid++ | Just uid <- lookupPackageName (ue_units unit_env) (PackageName pkg_fs)+ -> OtherPkg uid++ | otherwise+ -> OtherPkg (UnitId pkg_fs)+ -- not really correct as pkg_fs is unlikely to be a valid unit-id but+ -- we will report the failure later...+ -- | Calculate the 'ImportAvails' induced by an import of a particular -- interface, but without 'imp_mods'. calculateAvails :: HomeUnit@@ -564,7 +606,7 @@ addDiagnosticAt loc msg where mod = mi_module iface- loc = getLoc $ ideclName decl+ loc = getLocA $ ideclName decl is_qual = isImportDeclQualified (ideclQualified decl) has_import_list =@@ -652,7 +694,7 @@ -- See Note [GlobalRdrEnv shadowing] inBracket = isBrackStage stage - lcl_env_TH = lcl_env { tcl_rdr = delLocalRdrEnvList (tcl_rdr lcl_env) new_occs }+ lcl_env_TH = lcl_env { tcl_rdr = minusLocalRdrEnv (tcl_rdr lcl_env) new_occs } -- See Note [GlobalRdrEnv shadowing] lcl_env2 | inBracket = lcl_env_TH@@ -660,7 +702,7 @@ -- Deal with shadowing: see Note [GlobalRdrEnv shadowing] want_shadowing = isGHCi || inBracket- rdr_env1 | want_shadowing = shadowNames rdr_env new_names+ rdr_env1 | want_shadowing = shadowNames rdr_env new_occs | otherwise = rdr_env lcl_env3 = lcl_env2 { tcl_th_bndrs = extendNameEnvList th_bndrs@@ -677,7 +719,7 @@ ; return (gbl_env', lcl_env3) } where new_names = concatMap availGreNames avails- new_occs = map occName new_names+ new_occs = occSetToEnv (mkOccSet (map occName new_names)) -- If there is a fixity decl for the gre, add it to the fixity env extend_fix_env fix_env gre@@ -1769,7 +1811,7 @@ RealSrcLoc decl_loc _ -> Map.insertWith add decl_loc [gre] imp_map UnhelpfulLoc _ -> imp_map where- best_imp_spec = bestImport imp_specs+ best_imp_spec = bestImport (bagToList imp_specs) add _ gres = gre : gres warnUnusedImport :: WarningFlag -> NameEnv (FieldLabelString, Parent)@@ -1870,8 +1912,8 @@ | otherwise = do { let ImportDecl { ideclName = L _ mod_name , ideclSource = is_boot- , ideclPkgQual = mb_pkg } = decl- ; iface <- loadSrcInterface doc mod_name is_boot (fmap sl_fs mb_pkg)+ , ideclPkgQual = pkg_qual } = decl+ ; iface <- loadSrcInterface doc mod_name is_boot pkg_qual ; let used_avails = gresToAvailInfo used_gres lies = map (L l) (concatMap (to_ie iface) used_avails) ; return (L l (decl { ideclHiding = Just (False, L (l2l l) lies) })) }
compiler/GHC/Rename/Unbound.hs view
@@ -50,6 +50,7 @@ import Data.List (sortBy, partition, nub) import Data.Function ( on )+import GHC.Data.Bag {- ************************************************************************@@ -263,7 +264,7 @@ unquals_in_scope (gre@GRE { gre_lcl = lcl, gre_imp = is }) | lcl = [ Left (greDefinitionSrcSpan gre) ] | otherwise = [ Right ispec- | i <- is, let ispec = is_decl i+ | i <- bagToList is, let ispec = is_decl i , not (is_qual ispec) ] @@ -272,7 +273,7 @@ -- Ones for which *only* the qualified version is in scope quals_only (gre@GRE { gre_imp = is }) = [ (mkRdrQual (is_as ispec) (greOccName gre), Right ispec)- | i <- is, let ispec = is_decl i, is_qual ispec ]+ | i <- bagToList is, let ispec = is_decl i, is_qual ispec ] -- | Generate helpful suggestions if a qualified name Mod.foo is not in scope. importSuggestions :: LookingFor@@ -422,7 +423,7 @@ Nothing -> [] Just m -> [(moduleName m, Left (greDefinitionSrcSpan gre))] | otherwise = [ (is_as ispec, Right ispec)- | i <- is, let ispec = is_decl i ]+ | i <- bagToList is, let ispec = is_decl i ] isGreOk :: LookingFor -> GlobalRdrElt -> Bool isGreOk (LF what_look where_look) gre = what_ok && where_ok
compiler/GHC/Rename/Utils.hs view
@@ -65,6 +65,7 @@ import GHC.Settings.Constants ( mAX_TUPLE_SIZE, mAX_CTUPLE_SIZE ) import qualified Data.List.NonEmpty as NE import qualified GHC.LanguageExtensions as LangExt+import GHC.Data.Bag {- *********************************************************@@ -566,7 +567,7 @@ pp_qual name | lcl = ppr (nameModule name)- | imp : _ <- iss -- This 'imp' is the one that+ | Just imp <- headMaybe iss -- This 'imp' is the one that -- pprNameProvenance chooses , ImpDeclSpec { is_as = mod } <- is_decl imp = ppr mod
compiler/GHC/Runtime/Eval.hs view
@@ -81,7 +81,6 @@ import GHC.Tc.Types.Origin import GHC.Builtin.Names ( toDynName, pretendNameIsInScope )-import GHC.Builtin.Types ( isCTupleTyConName ) import GHC.Data.Maybe import GHC.Data.FastString@@ -107,6 +106,7 @@ import GHC.Types.Unique import GHC.Types.Unique.Supply import GHC.Types.TyThing+import GHC.Types.BreakInfo import GHC.Unit import GHC.Unit.Module.Graph@@ -233,7 +233,7 @@ evalStmt interp eval_opts (execWrap hval) let ic = hsc_IC hsc_env- bindings = (ic_tythings ic, ic_rn_gbl_env ic)+ bindings = (ic_tythings ic, ic_gre_cache ic) size = ghciHistSize idflags' @@ -310,7 +310,9 @@ emptyHistory size = nilBL size handleRunStatus :: GhcMonad m- => SingleStep -> String -> ([TyThing],GlobalRdrEnv) -> [Id]+ => SingleStep -> String+ -> ResumeBindings+ -> [Id] -> EvalStatus_ [ForeignHValue] [HValueRef] -> BoundedList History -> m ExecResult@@ -418,9 +420,9 @@ -- unbind the temporary locals by restoring the TypeEnv from -- before the breakpoint, and drop this Resume from the -- InteractiveContext.- let (resume_tmp_te,resume_rdr_env) = resumeBindings r+ let (resume_tmp_te,resume_gre_cache) = resumeBindings r ic' = ic { ic_tythings = resume_tmp_te,- ic_rn_gbl_env = resume_rdr_env,+ ic_gre_cache = resume_gre_cache, ic_resume = rs } setSession hsc_env{ hsc_IC = ic' } @@ -773,7 +775,7 @@ -- -- (setContext imports) sets the ic_imports field (which in turn -- determines what is in scope at the prompt) to 'imports', and--- constructs the ic_rn_glb_env environment to reflect it.+-- updates the icReaderEnv environment to reflect it. -- -- We retain in scope all the things defined at the prompt, and kept -- in ic_tythings. (Indeed, they shadow stuff from ic_imports.)@@ -788,10 +790,10 @@ liftIO $ throwGhcExceptionIO (formatError dflags mod err) Right all_env -> do { ; let old_ic = hsc_IC hsc_env- !final_rdr_env = all_env `icExtendGblRdrEnv` ic_tythings old_ic+ !final_gre_cache = ic_gre_cache old_ic `replaceImportEnv` all_env ; setSession- hsc_env{ hsc_IC = old_ic { ic_imports = imports- , ic_rn_gbl_env = final_rdr_env }}}}+ hsc_env{ hsc_IC = old_ic { ic_imports = imports+ , ic_gre_cache = final_gre_cache }}}} where formatError dflags mod err = ProgramError . showSDoc dflags $ text "Cannot add module" <+> ppr mod <+>@@ -856,7 +858,7 @@ case mb_stuff of Nothing -> return Nothing Just (thing, fixity, cls_insts, fam_insts, docs) -> do- let rdr_env = ic_rn_gbl_env (hsc_IC hsc_env)+ let rdr_env = icReaderEnv (hsc_IC hsc_env) -- Filter the instances based on whether the constituent names of their -- instance heads are all in scope.@@ -865,7 +867,7 @@ return (Just (thing, fixity, cls_insts', fam_insts', docs)) where plausible rdr_env names- -- Dfun involving only names that are in ic_rn_glb_env+ -- Dfun involving only names that are in icReaderEnv = allInfo || nameSetAll ok names where -- A name is ok if it's in the rdr_env,@@ -873,15 +875,14 @@ ok n | n == name = True -- The one we looked for in the first place! | pretendNameIsInScope n = True- | isBuiltInSyntax n = True- | isCTupleTyConName n = True+ -- See Note [pretendNameIsInScope] in GHC.Builtin.Names | isExternalName n = isJust (lookupGRE_Name rdr_env n) | otherwise = True -- | Returns all names in scope in the current interactive context getNamesInScope :: GhcMonad m => m [Name] getNamesInScope = withSession $ \hsc_env ->- return (map greMangledName (globalRdrEnvElts (ic_rn_gbl_env (hsc_IC hsc_env))))+ return (map greMangledName (globalRdrEnvElts (icReaderEnv (hsc_IC hsc_env)))) -- | Returns all 'RdrName's in scope in the current interactive -- context, excluding any that are internally-generated.@@ -889,7 +890,7 @@ getRdrNamesInScope = withSession $ \hsc_env -> do let ic = hsc_IC hsc_env- gbl_rdrenv = ic_rn_gbl_env ic+ gbl_rdrenv = icReaderEnv ic gbl_names = concatMap greRdrNames $ globalRdrEnvElts gbl_rdrenv -- Exclude internally generated names; see e.g. #11328 return (filter (not . isDerivedOccName . rdrNameOcc) gbl_names)
compiler/GHC/Settings/IO.hs view
@@ -140,10 +140,7 @@ let iserv_prog = libexec "ghc-iserv" ghcWithInterpreter <- getBooleanSetting "Use interpreter"- ghcWithSMP <- getBooleanSetting "Support SMP"- ghcRTSWays <- getSetting "RTS ways" useLibFFI <- getBooleanSetting "Use LibFFI"- ghcRtsWithLibdw <- getBooleanSetting "RTS expects libdw" return $ Settings { sGhcNameVersion = GhcNameVersion@@ -207,10 +204,7 @@ , sPlatformMisc = PlatformMisc { platformMisc_targetPlatformString = targetPlatformString , platformMisc_ghcWithInterpreter = ghcWithInterpreter- , platformMisc_ghcWithSMP = ghcWithSMP- , platformMisc_ghcRTSWays = ghcRTSWays , platformMisc_libFFI = useLibFFI- , platformMisc_ghcRtsWithLibdw = ghcRtsWithLibdw , platformMisc_llvmTarget = llvmTarget }
+ compiler/GHC/StgToCmm/Foreign.hs-boot view
@@ -0,0 +1,6 @@+module GHC.StgToCmm.Foreign where++import GHC.Cmm+import GHC.StgToCmm.Monad++emitPrimCall :: [CmmFormal] -> CallishMachOp -> [CmmActual] -> FCode ()
compiler/GHC/StgToCmm/Ticky.hs view
@@ -109,9 +109,10 @@ import GHC.StgToCmm.ArgRep ( slowCallPattern , toArgRep , argRepString ) import GHC.StgToCmm.Closure-import GHC.StgToCmm.Utils-import GHC.StgToCmm.Monad+import {-# SOURCE #-} GHC.StgToCmm.Foreign ( emitPrimCall ) import GHC.StgToCmm.Lit ( newStringCLit )+import GHC.StgToCmm.Monad+import GHC.StgToCmm.Utils import GHC.Stg.Syntax import GHC.Cmm.Expr@@ -339,30 +340,46 @@ already_registered <- tickyAllocdIsOn when (not already_registered) $ registerTickyCtr ctr_lbl +-- | Register a ticky counter.+--+-- It's important that this does not race with other entries of the same+-- closure, lest the ticky_entry_ctrs list may become cyclic. However, we also+-- need to make sure that this is reasonably efficient. Consequently, we first+-- perform a normal load of the counter's "registered" flag to check whether+-- registration is necessary. If so, then we do a compare-and-swap to lock the+-- counter for registration and use an atomic-exchange to add the counter to the list.+--+-- @+-- if ( f_ct.registeredp == 0 ) {+-- if (cas(f_ct.registeredp, 0, 1) == 0) {+-- old_head = xchg(ticky_entry_ctrs, f_ct);+-- f_ct.link = old_head;+-- }+-- }+-- @ registerTickyCtr :: CLabel -> FCode ()--- Register a ticky counter--- if ( ! f_ct.registeredp ) {--- f_ct.link = ticky_entry_ctrs; /* hook this one onto the front of the list */--- ticky_entry_ctrs = & (f_ct); /* mark it as "registered" */--- f_ct.registeredp = 1 } registerTickyCtr ctr_lbl = do platform <- getPlatform- let- constants = platformConstants platform- -- krc: code generator doesn't handle Not, so we test for Eq 0 instead- test = CmmMachOp (MO_Eq (wordWidth platform))- [CmmLoad (CmmLit (cmmLabelOffB ctr_lbl- (pc_OFFSET_StgEntCounter_registeredp constants))) (bWord platform),- zeroExpr platform]- register_stmts- = [ mkStore (CmmLit (cmmLabelOffB ctr_lbl (pc_OFFSET_StgEntCounter_link constants)))- (CmmLoad ticky_entry_ctrs (bWord platform))- , mkStore ticky_entry_ctrs (mkLblExpr ctr_lbl)- , mkStore (CmmLit (cmmLabelOffB ctr_lbl- (pc_OFFSET_StgEntCounter_registeredp constants)))- (mkIntExpr platform 1) ]- ticky_entry_ctrs = mkLblExpr (mkRtsCmmDataLabel (fsLit "ticky_entry_ctrs"))- emit =<< mkCmmIfThen test (catAGraphs register_stmts)+ let constants = platformConstants platform+ word_width = wordWidth platform+ registeredp = CmmLit (cmmLabelOffB ctr_lbl (pc_OFFSET_StgEntCounter_registeredp constants))++ register_stmts <- getCode $ do+ old_head <- newTemp (bWord platform)+ let ticky_entry_ctrs = mkLblExpr (mkRtsCmmDataLabel (fsLit "ticky_entry_ctrs"))+ link = CmmLit (cmmLabelOffB ctr_lbl (pc_OFFSET_StgEntCounter_link constants))+ emitPrimCall [old_head] (MO_Xchg word_width) [ticky_entry_ctrs, mkLblExpr ctr_lbl]+ emitStore link (CmmReg $ CmmLocal old_head)++ cas_test <- getCode $ do+ old <- newTemp (bWord platform)+ emitPrimCall [old] (MO_Cmpxchg word_width)+ [registeredp, zeroExpr platform, mkIntExpr platform 1]+ let locked = cmmEqWord platform (CmmReg $ CmmLocal old) (zeroExpr platform)+ emit =<< mkCmmIfThen locked register_stmts++ let test = cmmEqWord platform (CmmLoad registeredp (bWord platform)) (zeroExpr platform)+ emit =<< mkCmmIfThen test cas_test tickyReturnOldCon, tickyReturnNewCon :: RepArity -> FCode () tickyReturnOldCon arity
compiler/GHC/StgToCmm/Utils.hs view
@@ -276,8 +276,7 @@ -- the optimization pass doesn't have to do as much work) assignTemp (CmmReg (CmmLocal reg)) = return reg assignTemp e = do { platform <- getPlatform- ; uniq <- newUnique- ; let reg = LocalReg uniq (cmmExprType platform e)+ ; reg <- newTemp (cmmExprType platform e) ; emitAssign (CmmLocal reg) e ; return reg }
compiler/GHC/Tc/Deriv.hs view
@@ -22,7 +22,6 @@ import GHC.Tc.Utils.Monad import GHC.Tc.Instance.Family import GHC.Tc.Types.Origin-import GHC.Core.Predicate import GHC.Tc.Deriv.Infer import GHC.Tc.Deriv.Utils import GHC.Tc.TyCl.Class( instDeclCtxt3, tcATDefault )@@ -47,7 +46,6 @@ import GHC.Utils.Error import GHC.Core.DataCon import GHC.Data.Maybe-import GHC.Types.Hint import GHC.Types.Name.Reader import GHC.Types.Name import GHC.Types.Name.Set as NameSet@@ -513,7 +511,7 @@ , text "via_tvs" <+> ppr via_tvs ] (cls_tvs, cls, cls_tys, cls_arg_kinds) <- tcHsDeriv deriv_pred when (cls_arg_kinds `lengthIsNot` 1) $- failWithTc (nonUnaryErr deriv_pred)+ failWithTc (TcRnNonUnaryTypeclassConstraint deriv_pred) let [cls_arg_kind] = cls_arg_kinds mb_deriv_strat = fmap unLoc mb_lderiv_strat if (className cls == typeableClassName)@@ -658,8 +656,8 @@ mb_match = tcUnifyTy inst_ty_kind via_kind checkTc (isJust mb_match)- (derivingViaKindErr cls inst_ty_kind- via_ty via_kind)+ (TcRnCannotDeriveInstance cls mempty Nothing NoGeneralizedNewtypeDeriving $+ DerivErrDerivingViaWrongKind inst_ty_kind via_ty via_kind) let Just kind_subst = mb_match ki_subst_range = getTCvSubstRangeFVs kind_subst@@ -739,11 +737,7 @@ pure (tvs, SupplyContext theta, cls, inst_tys) warnUselessTypeable :: TcM ()-warnUselessTypeable- = do { addDiagnosticTc $ TcRnUnknownMessage- $ mkPlainDiagnostic (WarningWithFlag Opt_WarnDerivingTypeable) noHints $- text "Deriving" <+> quotes (ppr typeableClassName) <+>- text "has no effect: all types now auto-derive Typeable" }+warnUselessTypeable = addDiagnosticTc TcRnUselessTypeable ------------------------------------------------------------------ deriveTyData :: TyCon -> [Type] -- LHS of data or data instance@@ -779,7 +773,8 @@ -- Check that the result really is well-kinded ; checkTc (enough_args && isJust mb_match)- (derivingKindErr tc cls cls_tys cls_arg_kind enough_args)+ (TcRnCannotDeriveInstance cls cls_tys Nothing NoGeneralizedNewtypeDeriving $+ DerivErrNotWellKinded tc cls_arg_kind n_args_to_keep) ; let -- Returns a singleton-element list if using ViaStrategy and an -- empty list otherwise. Useful for free-variable calculations.@@ -824,7 +819,8 @@ via_match = tcUnifyTy inst_ty_kind via_kind checkTc (isJust via_match)- (derivingViaKindErr cls inst_ty_kind via_ty via_kind)+ (TcRnCannotDeriveInstance cls mempty Nothing NoGeneralizedNewtypeDeriving $+ DerivErrDerivingViaWrongKind inst_ty_kind via_ty via_kind) let Just via_subst = via_match pure $ propagate_subst via_subst tkvs' cls_tys'@@ -845,7 +841,8 @@ ; let final_tc_app = mkTyConApp tc final_tc_args final_cls_args = final_cls_tys ++ [final_tc_app] ; checkTc (allDistinctTyVars (mkVarSet final_tkvs) args_to_drop) -- (a, b, c)- (derivingEtaErr cls final_cls_tys final_tc_app)+ (TcRnCannotDeriveInstance cls final_cls_tys Nothing NoGeneralizedNewtypeDeriving $+ DerivErrNoEtaReduce final_tc_app) -- Check that -- (a) The args to drop are all type variables; eg reject: -- data instance T a Int = .... deriving( Monad )@@ -1154,9 +1151,7 @@ mkEqnHelp overlap_mode tvs cls cls_args deriv_ctxt deriv_strat = do is_boot <- tcIsHsBootOrSig- when is_boot $- bale_out (text "Cannot derive instances in hs-boot files"- $+$ text "Write an instance declaration instead")+ when is_boot $ bale_out DerivErrBootFileFound runReaderT mk_eqn deriv_env where deriv_env = DerivEnv { denv_overlap_mode = overlap_mode@@ -1166,7 +1161,8 @@ , denv_ctxt = deriv_ctxt , denv_strat = deriv_strat } - bale_out msg = failWithTc $ derivingThingErr False cls cls_args deriv_strat msg+ bale_out =+ failWithTc . TcRnCannotDeriveInstance cls cls_args deriv_strat NoGeneralizedNewtypeDeriving mk_eqn :: DerivM EarlyDerivSpec mk_eqn = do@@ -1188,7 +1184,7 @@ (cls_tys, inst_ty) <- expectNonNullaryClsArgs cls_args dit <- expectAlgTyConApp cls_tys inst_ty unless (isNewTyCon (dit_rep_tc dit)) $- derivingThingFailWith False gndNonNewtypeErr+ derivingThingFailWith NoGeneralizedNewtypeDeriving DerivErrGNDUsedOnData mkNewTypeEqn True dit Nothing -> mk_eqn_no_strategy@@ -1200,7 +1196,7 @@ -- property is important. expectNonNullaryClsArgs :: [Type] -> DerivM ([Type], Type) expectNonNullaryClsArgs inst_tys =- maybe (derivingThingFailWith False derivingNullaryErr) pure $+ maybe (derivingThingFailWith NoGeneralizedNewtypeDeriving DerivErrNullaryClasses) pure $ snocView inst_tys -- @expectAlgTyConApp cls_tys inst_ty@ checks if @inst_ty@ is an application@@ -1217,9 +1213,7 @@ expectAlgTyConApp cls_tys inst_ty = do fam_envs <- lift tcGetFamInstEnvs case mk_deriv_inst_tys_maybe fam_envs cls_tys inst_ty of- Nothing -> derivingThingFailWith False $- text "The last argument of the instance must be a"- <+> text "data or newtype application"+ Nothing -> derivingThingFailWith NoGeneralizedNewtypeDeriving DerivErrLastArgMustBeApp Just dit -> do expectNonDataFamTyCon dit pure dit @@ -1234,8 +1228,8 @@ , dit_rep_tc = rep_tc }) = -- If it's still a data family, the lookup failed; i.e no instance exists when (isDataFamilyTyCon rep_tc) $- derivingThingFailWith False $- text "No family instance for" <+> quotes (pprTypeApp tc tc_args)+ derivingThingFailWith NoGeneralizedNewtypeDeriving $+ DerivErrNoFamilyInstance tc tc_args mk_deriv_inst_tys_maybe :: FamInstEnvs -> [Type] -> Type -> Maybe DerivInstTys@@ -1362,20 +1356,31 @@ = do DerivEnv { denv_cls = cls , denv_ctxt = deriv_ctxt } <- ask dflags <- getDynFlags+ let isDeriveAnyClassEnabled =+ deriveAnyClassEnabled (xopt LangExt.DeriveAnyClass dflags) case checkOriginativeSideConditions dflags deriv_ctxt cls cls_tys tc rep_tc of CanDeriveStock gen_fn -> mk_eqn_from_mechanism $ DerivSpecStock { dsm_stock_dit = dit , dsm_stock_gen_fn = gen_fn }- StockClassError msg -> derivingThingFailWith False msg- _ -> derivingThingFailWith False (nonStdErr cls)+ StockClassError why -> derivingThingFailWith NoGeneralizedNewtypeDeriving why+ CanDeriveAnyClass -> derivingThingFailWith NoGeneralizedNewtypeDeriving+ (DerivErrNotStockDeriveable isDeriveAnyClassEnabled)+ -- In the 'NonDerivableClass' case we can't derive with either stock or anyclass+ -- so we /don't want/ to suggest the user to enabled 'DeriveAnyClass', that's+ -- why we pass 'YesDeriveAnyClassEnabled', so that GHC won't attempt to suggest it.+ NonDerivableClass -> derivingThingFailWith NoGeneralizedNewtypeDeriving+ (DerivErrNotStockDeriveable YesDeriveAnyClassEnabled) mk_eqn_anyclass :: DerivM EarlyDerivSpec mk_eqn_anyclass = do dflags <- getDynFlags- case canDeriveAnyClass dflags of- IsValid -> mk_eqn_from_mechanism DerivSpecAnyClass- NotValid msg -> derivingThingFailWith False msg+ let isDeriveAnyClassEnabled =+ deriveAnyClassEnabled (xopt LangExt.DeriveAnyClass dflags)+ case xopt LangExt.DeriveAnyClass dflags of+ True -> mk_eqn_from_mechanism DerivSpecAnyClass+ False -> derivingThingFailWith NoGeneralizedNewtypeDeriving+ (DerivErrNotDeriveable isDeriveAnyClassEnabled) mk_eqn_newtype :: DerivInstTys -- Information about the arguments to the class -> Type -- The newtype's representation type@@ -1432,24 +1437,24 @@ DerivEnv { denv_cls = cls , denv_ctxt = deriv_ctxt } <- ask dflags <- getDynFlags+ let isDeriveAnyClassEnabled =+ deriveAnyClassEnabled (xopt LangExt.DeriveAnyClass dflags) -- See Note [Deriving instances for classes themselves]- let dac_error msg+ let dac_error | isClassTyCon rep_tc- = quotes (ppr tc) <+> text "is a type class,"- <+> text "and can only have a derived instance"- $+$ text "if DeriveAnyClass is enabled"+ = DerivErrOnlyAnyClassDeriveable tc isDeriveAnyClassEnabled | otherwise- = nonStdErr cls $$ msg+ = DerivErrNotStockDeriveable isDeriveAnyClassEnabled case checkOriginativeSideConditions dflags deriv_ctxt cls cls_tys tc rep_tc of- NonDerivableClass msg -> derivingThingFailWith False (dac_error msg)- StockClassError msg -> derivingThingFailWith False msg- CanDeriveStock gen_fn -> mk_eqn_from_mechanism $- DerivSpecStock { dsm_stock_dit = dit- , dsm_stock_gen_fn = gen_fn }- CanDeriveAnyClass -> mk_eqn_from_mechanism DerivSpecAnyClass+ NonDerivableClass -> derivingThingFailWith NoGeneralizedNewtypeDeriving dac_error+ StockClassError why -> derivingThingFailWith NoGeneralizedNewtypeDeriving why+ CanDeriveStock gen_fn -> mk_eqn_from_mechanism $+ DerivSpecStock { dsm_stock_dit = dit+ , dsm_stock_gen_fn = gen_fn }+ CanDeriveAnyClass -> mk_eqn_from_mechanism DerivSpecAnyClass {- ************************************************************************@@ -1482,11 +1487,7 @@ let newtype_deriving = xopt LangExt.GeneralizedNewtypeDeriving dflags deriveAnyClass = xopt LangExt.DeriveAnyClass dflags - bale_out = derivingThingFailWith newtype_deriving-- non_std = nonStdErr cls- suggest_gnd = text "Try GeneralizedNewtypeDeriving for GHC's"- <+> text "newtype-deriving extension"+ bale_out = derivingThingFailWith (usingGeneralizedNewtypeDeriving newtype_deriving) -- Here is the plan for newtype derivings. We see -- newtype T a1...an = MkT (t ak+1...an)@@ -1555,9 +1556,6 @@ -- And the [a] must not mention 'b'. That's all handled -- by nt_eta_rity. - cant_derive_err = ppUnless eta_ok eta_msg- eta_msg = text "cannot eta-reduce the representation type enough"- massert (cls_tys `lengthIs` (classArity cls - 1)) if newtype_strat then@@ -1569,8 +1567,7 @@ -- See Note [Determining whether newtype-deriving is appropriate] if eta_ok && newtype_deriving then mk_eqn_newtype dit rep_inst_ty- else bale_out (cant_derive_err $$- if newtype_deriving then empty else suggest_gnd)+ else bale_out (DerivErrCannotEtaReduceEnough eta_ok) else if might_be_newtype_derivable && ((newtype_deriving && not deriveAnyClass)@@ -1578,7 +1575,7 @@ then mk_eqn_newtype dit rep_inst_ty else case checkOriginativeSideConditions dflags deriv_ctxt cls cls_tys tycon rep_tycon of- StockClassError msg+ StockClassError why -- There's a particular corner case where -- -- 1. -XGeneralizedNewtypeDeriving and -XDeriveAnyClass are@@ -1592,18 +1589,18 @@ -> mk_eqn_newtype dit rep_inst_ty -- Otherwise, throw an error for a stock class | might_be_newtype_derivable && not newtype_deriving- -> bale_out (msg $$ suggest_gnd)+ -> bale_out why | otherwise- -> bale_out msg+ -> bale_out why -- Must use newtype deriving or DeriveAnyClass- NonDerivableClass _msg+ NonDerivableClass -- Too hard, even with newtype deriving- | newtype_deriving -> bale_out cant_derive_err+ | newtype_deriving -> bale_out (DerivErrCannotEtaReduceEnough eta_ok) -- Try newtype deriving! -- Here we suggest GeneralizedNewtypeDeriving even in cases -- where it may not be applicable. See #9600.- | otherwise -> bale_out (non_std $$ suggest_gnd)+ | otherwise -> bale_out DerivErrNewtypeNonDeriveableClass -- DeriveAnyClass CanDeriveAnyClass -> do@@ -1613,16 +1610,7 @@ -- See Note [Deriving strategies] when (newtype_deriving && deriveAnyClass) $ lift $ addDiagnosticTc- $ TcRnUnknownMessage- $ mkPlainDiagnostic (WarningWithFlag Opt_WarnDerivingDefaults) noHints- $ sep- [ text "Both DeriveAnyClass and"- <+> text "GeneralizedNewtypeDeriving are enabled"- , text "Defaulting to the DeriveAnyClass strategy"- <+> text "for instantiating" <+> ppr cls- , text "Use DerivingStrategies to pick"- <+> text "a different strategy"- ]+ $ TcRnDerivingDefaults cls mk_eqn_from_mechanism DerivSpecAnyClass -- CanDeriveStock CanDeriveStock gen_fn -> mk_eqn_from_mechanism $@@ -1931,7 +1919,7 @@ lift $ addUsedDataCons rdr_env rep_tc unless (not hidden_data_cons) $- bale_out $ derivingHiddenErr tc+ bale_out $ DerivErrDataConsNotAllInScope tc -- Ensure that a class's associated type variables are suitable for -- GeneralizedNewtypeDeriving or DerivingVia. Unsurprisingly, this check is@@ -1970,24 +1958,12 @@ last_cls_tv = assert (notNull cls_tyvars ) last cls_tyvars - cant_derive_err- = vcat [ ppUnless no_adfs adfs_msg- , maybe empty at_without_last_cls_tv_msg- at_without_last_cls_tv- , maybe empty at_last_cls_tv_in_kinds_msg- at_last_cls_tv_in_kinds- ]- adfs_msg = text "the class has associated data types"- at_without_last_cls_tv_msg at_tc = hang- (text "the associated type" <+> quotes (ppr at_tc)- <+> text "is not parameterized over the last type variable")- 2 (text "of the class" <+> quotes (ppr cls))- at_last_cls_tv_in_kinds_msg at_tc = hang- (text "the associated type" <+> quotes (ppr at_tc)- <+> text "contains the last type variable")- 2 (text "of the class" <+> quotes (ppr cls)- <+> text "in a kind, which is not (yet) allowed")- unless ats_look_sensible $ bale_out cant_derive_err+ unless ats_look_sensible $+ bale_out (DerivErrHasAssociatedDatatypes+ (hasAssociatedDataFamInsts (not no_adfs))+ (associatedTyLastVarInKind at_last_cls_tv_in_kinds)+ (associatedTyNotParamOverLastTyVar at_without_last_cls_tv)+ ) doDerivInstErrorChecks2 :: Class -> ClsInst -> ThetaType -> Maybe SrcSpan -> DerivSpecMechanism -> TcM ()@@ -2004,39 +1980,28 @@ ; case wildcard of Nothing -> pure () Just span -> setSrcSpan span $ do- checkTc xpartial_sigs (partial_sig_msg [pts_suggestion])- diagnosticTc wpartial_sigs (partial_sig_msg noHints)+ let suggParSigs = suggestPartialTypeSignatures xpartial_sigs+ let dia = TcRnPartialTypeSignatures suggParSigs theta+ checkTc xpartial_sigs dia+ diagnosticTc wpartial_sigs dia -- Check for Generic instances that are derived with an exotic -- deriving strategy like DAC -- See Note [Deriving strategies] ; when (exotic_mechanism && className clas `elem` genericClassNames) $- do { failIfTc (safeLanguageOn dflags) gen_inst_err+ do { failIfTc (safeLanguageOn dflags)+ (TcRnCannotDeriveInstance clas mempty Nothing NoGeneralizedNewtypeDeriving $+ DerivErrSafeHaskellGenericInst) ; when (safeInferOn dflags) (recordUnsafeInfer emptyMessages) } } where exotic_mechanism = not $ isDerivSpecStock mechanism - partial_sig_msg :: [GhcHint] -> TcRnMessage- partial_sig_msg hints = TcRnUnknownMessage- $ mkPlainDiagnostic (WarningWithFlag Opt_WarnPartialTypeSignatures) hints $- text "Found type wildcard" <+> quotes (char '_')- <+> text "standing for" <+> quotes (pprTheta theta)-- pts_suggestion :: GhcHint- pts_suggestion- = UnknownHint (text "To use the inferred type, enable PartialTypeSignatures")-- gen_inst_err :: TcRnMessage- gen_inst_err = TcRnUnknownMessage- $ mkPlainError noHints $- text "Generic instances can only be derived in"- <+> text "Safe Haskell using the stock strategy."--derivingThingFailWith :: Bool -- If True, add a snippet about how not even- -- GeneralizedNewtypeDeriving would make this- -- declaration work. This only kicks in when- -- an explicit deriving strategy is not given.- -> SDoc -- The error message+derivingThingFailWith :: UsingGeneralizedNewtypeDeriving+ -- ^ If 'YesGeneralizedNewtypeDeriving', add a snippet about+ -- how not even GeneralizedNewtypeDeriving would make this+ -- declaration work. This only kicks in when+ -- an explicit deriving strategy is not given.+ -> DeriveInstanceErrReason -- The reason the derivation failed -> DerivM a derivingThingFailWith newtype_deriving msg = do err <- derivingThingErrM newtype_deriving msg@@ -2067,7 +2032,7 @@ tyfam_insts <- -- canDeriveAnyClass should ensure that this code can't be reached -- unless -XDeriveAnyClass is enabled.- assertPpr (isValid (canDeriveAnyClass dflags))+ assertPpr (xopt LangExt.DeriveAnyClass dflags) (ppr "genDerivStuff: bad derived class" <+> ppr clas) $ mapM (tcATDefault loc mini_subst emptyNameSet) (classATItems clas)@@ -2218,100 +2183,26 @@ ************************************************************************ -} -nonUnaryErr :: LHsSigType GhcRn -> TcRnMessage-nonUnaryErr ct = TcRnUnknownMessage $ mkPlainError noHints $- quotes (ppr ct)- <+> text "is not a unary constraint, as expected by a deriving clause"--nonStdErr :: Class -> SDoc-nonStdErr cls =- quotes (ppr cls)- <+> text "is not a stock derivable class (Eq, Show, etc.)"--gndNonNewtypeErr :: SDoc-gndNonNewtypeErr =- text "GeneralizedNewtypeDeriving cannot be used on non-newtypes"--derivingNullaryErr :: SDoc-derivingNullaryErr = text "Cannot derive instances for nullary classes"--derivingKindErr :: TyCon -> Class -> [Type] -> Kind -> Bool -> TcRnMessage-derivingKindErr tc cls cls_tys cls_kind enough_args- = TcRnUnknownMessage $ mkPlainError noHints $- sep [ hang (text "Cannot derive well-kinded instance of form"- <+> quotes (pprClassPred cls cls_tys- <+> parens (ppr tc <+> text "...")))- 2 gen1_suggestion- , nest 2 (text "Class" <+> quotes (ppr cls)- <+> text "expects an argument of kind"- <+> quotes (pprKind cls_kind))- ]- where- gen1_suggestion | cls `hasKey` gen1ClassKey && enough_args- = text "(Perhaps you intended to use PolyKinds)"- | otherwise = Outputable.empty--derivingViaKindErr :: Class -> Kind -> Type -> Kind -> TcRnMessage-derivingViaKindErr cls cls_kind via_ty via_kind- = TcRnUnknownMessage $ mkPlainDiagnostic ErrorWithoutFlag noHints $- hang (text "Cannot derive instance via" <+> quotes (pprType via_ty))- 2 (text "Class" <+> quotes (ppr cls)- <+> text "expects an argument of kind"- <+> quotes (pprKind cls_kind) <> char ','- $+$ text "but" <+> quotes (pprType via_ty)- <+> text "has kind" <+> quotes (pprKind via_kind))--derivingEtaErr :: Class -> [Type] -> Type -> TcRnMessage-derivingEtaErr cls cls_tys inst_ty- = TcRnUnknownMessage $ mkPlainDiagnostic ErrorWithoutFlag noHints $- sep [text "Cannot eta-reduce to an instance of form",- nest 2 (text "instance (...) =>"- <+> pprClassPred cls (cls_tys ++ [inst_ty]))]--derivingThingErr :: Bool -> Class -> [Type]- -> Maybe (DerivStrategy GhcTc) -> SDoc -> TcRnMessage-derivingThingErr newtype_deriving cls cls_args mb_strat why- = derivingThingErr' newtype_deriving cls cls_args mb_strat- (maybe empty derivStrategyName mb_strat) why--derivingThingErrM :: Bool -> SDoc -> DerivM TcRnMessage+derivingThingErrM :: UsingGeneralizedNewtypeDeriving+ -> DeriveInstanceErrReason+ -> DerivM TcRnMessage derivingThingErrM newtype_deriving why = do DerivEnv { denv_cls = cls , denv_inst_tys = cls_args , denv_strat = mb_strat } <- ask- pure $ derivingThingErr newtype_deriving cls cls_args mb_strat why+ pure $ TcRnCannotDeriveInstance cls cls_args mb_strat newtype_deriving why -derivingThingErrMechanism :: DerivSpecMechanism -> SDoc -> DerivM TcRnMessage+derivingThingErrMechanism :: DerivSpecMechanism -> DeriveInstanceErrReason -> DerivM TcRnMessage derivingThingErrMechanism mechanism why = do DerivEnv { denv_cls = cls , denv_inst_tys = cls_args , denv_strat = mb_strat } <- ask- pure $ derivingThingErr' (isDerivSpecNewtype mechanism) cls cls_args mb_strat- (derivStrategyName $ derivSpecMechanismToStrategy mechanism) why--derivingThingErr' :: Bool -> Class -> [Type]- -> Maybe (DerivStrategy GhcTc) -> SDoc -> SDoc -> TcRnMessage-derivingThingErr' newtype_deriving cls cls_args mb_strat strat_msg why- = TcRnUnknownMessage $ mkPlainError noHints $- sep [(hang (text "Can't make a derived instance of")- 2 (quotes (ppr pred) <+> via_mechanism)- $$ nest 2 extra) <> colon,- nest 2 why]+ pure $ TcRnCannotDeriveInstance cls cls_args mb_strat newtype_deriving why where- strat_used = isJust mb_strat- extra | not strat_used, newtype_deriving- = text "(even with cunning GeneralizedNewtypeDeriving)"- | otherwise = empty- pred = mkClassPred cls cls_args- via_mechanism | strat_used- = text "with the" <+> strat_msg <+> text "strategy"- | otherwise- = empty--derivingHiddenErr :: TyCon -> SDoc-derivingHiddenErr tc- = hang (text "The data constructors of" <+> quotes (ppr tc) <+> text "are not all in scope")- 2 (text "so you cannot derive an instance for it")+ newtype_deriving :: UsingGeneralizedNewtypeDeriving+ newtype_deriving+ = if isDerivSpecNewtype mechanism then YesGeneralizedNewtypeDeriving+ else NoGeneralizedNewtypeDeriving standaloneCtxt :: LHsSigWcType GhcRn -> SDoc standaloneCtxt ty = hang (text "In the stand-alone deriving instance for")
compiler/GHC/Tc/Deriv/Functor.hs view
@@ -807,12 +807,15 @@ where data_cons = getPossibleDataCons tycon tycon_args + foldr_name = L (noAnnSrcSpan loc) foldable_foldr_RDR+ foldr_bind = mkRdrFunBind (L (noAnnSrcSpan loc) foldable_foldr_RDR) eqns eqns = map foldr_eqn data_cons foldr_eqn con = evalState (match_foldr z_Expr [f_Pat,z_Pat] con =<< parts) bs_RDRs where parts = sequence $ foldDataConArgs ft_foldr con+ foldr_match_ctxt = mkPrefixFunRhs foldr_name foldMap_name = L (noAnnSrcSpan loc) foldMap_RDR @@ -826,6 +829,7 @@ = evalState (match_foldMap [f_Pat] con =<< parts) bs_RDRs where parts = sequence $ foldDataConArgs ft_foldMap con+ foldMap_match_ctxt = mkPrefixFunRhs foldMap_name -- Given a list of NullM results, produce Nothing if any of -- them is NotNull, and otherwise produce a list of Maybes@@ -881,7 +885,7 @@ -> DataCon -> [Maybe (LHsExpr GhcPs)] -> m (LMatch GhcPs (LHsExpr GhcPs))- match_foldr z = mkSimpleConMatch2 LambdaExpr $ \_ xs -> return (mkFoldr xs)+ match_foldr z = mkSimpleConMatch2 foldr_match_ctxt $ \_ xs -> return (mkFoldr xs) where -- g1 v1 (g2 v2 (.. z)) mkFoldr :: [LHsExpr GhcPs] -> LHsExpr GhcPs@@ -911,7 +915,7 @@ -> DataCon -> [Maybe (LHsExpr GhcPs)] -> m (LMatch GhcPs (LHsExpr GhcPs))- match_foldMap = mkSimpleConMatch2 CaseAlt $ \_ xs -> return (mkFoldMap xs)+ match_foldMap = mkSimpleConMatch2 foldMap_match_ctxt $ \_ xs -> return (mkFoldMap xs) where -- mappend v1 (mappend v2 ..) mkFoldMap :: [LHsExpr GhcPs] -> LHsExpr GhcPs@@ -1042,6 +1046,7 @@ = evalState (match_for_con [f_Pat] con =<< parts) bs_RDRs where parts = sequence $ foldDataConArgs ft_trav con+ traverse_match_ctxt = mkPrefixFunRhs traverse_name -- Yields 'Just' an expression if we're folding over a type that mentions -- the last type parameter of the datatype. Otherwise, yields 'Nothing'.@@ -1072,7 +1077,7 @@ -> DataCon -> [Maybe (LHsExpr GhcPs)] -> m (LMatch GhcPs (LHsExpr GhcPs))- match_for_con = mkSimpleConMatch2 CaseAlt $+ match_for_con = mkSimpleConMatch2 traverse_match_ctxt $ \con xs -> return (mkApCon con xs) where -- liftA2 (\b1 b2 ... -> Con b1 b2 ...) x1 x2 <*> ..
compiler/GHC/Tc/Deriv/Generics.hs view
@@ -27,6 +27,7 @@ import GHC.Tc.Utils.TcType import GHC.Tc.Deriv.Generate import GHC.Tc.Deriv.Functor+import GHC.Tc.Errors.Types import GHC.Core.DataCon import GHC.Core.TyCon import GHC.Core.FamInstEnv ( FamInst, FamFlavor(..), mkSingleCoAxiom )@@ -47,7 +48,7 @@ import GHC.Tc.Utils.Env import GHC.Tc.Utils.Monad import GHC.Driver.Session-import GHC.Utils.Error( Validity(..), andValid )+import GHC.Utils.Error( Validity'(..), andValid ) import GHC.Types.SrcLoc import GHC.Data.Bag import GHC.Types.Var.Env@@ -146,7 +147,7 @@ -} -canDoGenerics :: TyCon -> Validity+canDoGenerics :: TyCon -> Validity' [DeriveGenericsErrReason] -- canDoGenerics determines if Generic/Rep can be derived. -- -- Check (a) from Note [Requirements for deriving Generic and Rep] is taken@@ -158,14 +159,14 @@ = mergeErrors ( -- Check (b) from Note [Requirements for deriving Generic and Rep]. (if (not (null (tyConStupidTheta tc)))- then (NotValid (tc_name <+> text "must not have a datatype context"))+ then (NotValid $ DerivErrGenericsMustNotHaveDatatypeContext tc_name) else IsValid) -- See comment below : (map bad_con (tyConDataCons tc))) where -- The tc can be a representation tycon. When we want to display it to the -- user (in an error message) we should print its parent- tc_name = ppr $ case tyConFamInst_maybe tc of+ tc_name = case tyConFamInst_maybe tc of Just (ptc, _) -> ptc _ -> tc @@ -175,12 +176,12 @@ -- then we can't build the embedding-projection pair, because -- it relies on instantiating *polymorphic* sum and product types -- at the argument types of the constructors- bad_con dc = if (any bad_arg_type (map scaledThing $ dataConOrigArgTys dc))- then (NotValid (ppr dc <+> text- "must not have exotic unlifted or polymorphic arguments"))- else (if (not (isVanillaDataCon dc))- then (NotValid (ppr dc <+> text "must be a vanilla data constructor"))- else IsValid)+ bad_con :: DataCon -> Validity' DeriveGenericsErrReason+ bad_con dc = if any bad_arg_type (map scaledThing $ dataConOrigArgTys dc)+ then NotValid $ DerivErrGenericsMustNotHaveExoticArgs dc+ else if not (isVanillaDataCon dc)+ then NotValid $ DerivErrGenericsMustBeVanillaDataCon dc+ else IsValid -- Nor can we do the job if it's an existential data constructor, -- Nor if the args are polymorphic types (I don't think)@@ -194,19 +195,20 @@ allowedUnliftedTy :: Type -> Bool allowedUnliftedTy = isJust . unboxedRepRDRs -mergeErrors :: [Validity] -> Validity+mergeErrors :: [Validity' a] -> Validity' [a] mergeErrors [] = IsValid mergeErrors (NotValid s:t) = case mergeErrors t of- IsValid -> NotValid s- NotValid s' -> NotValid (s <> text ", and" $$ s')+ IsValid -> NotValid [s]+ NotValid s' -> NotValid (s : s') mergeErrors (IsValid : t) = mergeErrors t+ -- NotValid s' -> NotValid (s <> text ", and" $$ s') -- A datatype used only inside of canDoGenerics1. It's the result of analysing -- a type term. data Check_for_CanDoGenerics1 = CCDG1 { _ccdg1_hasParam :: Bool -- does the parameter of interest occurs in -- this type?- , _ccdg1_errors :: Validity -- errors generated by this type+ , _ccdg1_errors :: Validity' DeriveGenericsErrReason -- errors generated by this type } {-@@ -241,15 +243,14 @@ -- -- It returns IsValid if deriving is possible. It returns (NotValid reason) -- if not.-canDoGenerics1 :: TyCon -> Validity+canDoGenerics1 :: TyCon -> Validity' [DeriveGenericsErrReason] canDoGenerics1 rep_tc = canDoGenerics rep_tc `andValid` additionalChecks where additionalChecks -- check (d) from Note [Requirements for deriving Generic and Rep]- | null (tyConTyVars rep_tc) = NotValid $- text "Data type" <+> quotes (ppr rep_tc)- <+> text "must have some type parameters"+ | null (tyConTyVars rep_tc) = NotValid [+ DerivErrGenericsMustHaveSomeTypeParams rep_tc] | otherwise = mergeErrors $ concatMap check_con data_cons @@ -258,15 +259,12 @@ j@(NotValid {}) -> [j] IsValid -> _ccdg1_errors `map` foldDataConArgs (ft_check con) con - bad :: DataCon -> SDoc -> SDoc- bad con msg = text "Constructor" <+> quotes (ppr con) <+> msg-- check_vanilla :: DataCon -> Validity+ check_vanilla :: DataCon -> Validity' DeriveGenericsErrReason check_vanilla con | isVanillaDataCon con = IsValid- | otherwise = NotValid (bad con existential)+ | otherwise = NotValid $ DerivErrGenericsMustNotHaveExistentials con - bmzero = CCDG1 False IsValid- bmbad con s = CCDG1 True $ NotValid $ bad con s+ bmzero = CCDG1 False IsValid+ bmbad con = CCDG1 True $ NotValid (DerivErrGenericsWrongArgKind con) bmplus (CCDG1 b1 m1) (CCDG1 b2 m2) = CCDG1 (b1 || b2) (m1 `andValid` m2) -- check (e) from Note [Requirements for deriving Generic and Rep]@@ -279,29 +277,24 @@ -- (component_0,component_1,...,component_n) , ft_tup = \_ components -> if any _ccdg1_hasParam (init components)- then bmbad con wrong_arg+ then bmbad con else foldr bmplus bmzero components -- (dom -> rng), where the head of ty is not a tuple tycon , ft_fun = \dom rng -> -- cf #8516 if _ccdg1_hasParam dom- then bmbad con wrong_arg+ then bmbad con else bmplus dom rng -- (ty arg), where head of ty is neither (->) nor a tuple constructor and -- the parameter of interest does not occur in ty , ft_ty_app = \_ _ arg -> arg - , ft_bad_app = bmbad con wrong_arg+ , ft_bad_app = bmbad con , ft_forall = \_ body -> body -- polytypes are handled elsewhere } where caseVar = CCDG1 True IsValid--- existential = text "must not have existential arguments"- wrong_arg = text "applies a type to an argument involving the last parameter"- $$ text "but the applied type is not of kind * -> *" {- ************************************************************************
compiler/GHC/Tc/Deriv/Utils.hs view
@@ -17,7 +17,6 @@ PredOrigin(..), ThetaOrigin(..), mkPredOrigin, mkThetaOrigin, mkThetaOriginFromPreds, substPredOrigin, checkOriginativeSideConditions, hasStockDeriving,- canDeriveAnyClass, std_class_via_coercible, non_coercible_class, newDerivClsInst, extendLocalInstEnv ) where@@ -45,13 +44,13 @@ import GHC.Tc.Deriv.Generate import GHC.Tc.Deriv.Functor import GHC.Tc.Deriv.Generics+import GHC.Tc.Errors.Types import GHC.Tc.Types.Origin import GHC.Tc.Utils.Monad import GHC.Tc.Utils.TcType import GHC.Builtin.Names.TH (liftClassKey) import GHC.Core.TyCon import GHC.Core.Multiplicity-import GHC.Core.TyCo.Ppr (pprSourceTyCon) import GHC.Core.Type import GHC.Utils.Misc import GHC.Types.Var.Set@@ -432,9 +431,9 @@ = CanDeriveStock -- Stock class, can derive (SrcSpan -> TyCon -> [Type] -> [Type] -> TcM (LHsBinds GhcPs, [LSig GhcPs], BagDerivStuff, [Name]))- | StockClassError SDoc -- Stock class, but can't do it+ | StockClassError !DeriveInstanceErrReason -- Stock class, but can't do it | CanDeriveAnyClass -- See Note [Deriving any class]- | NonDerivableClass SDoc -- Cannot derive with either stock or anyclass+ | NonDerivableClass -- Cannot derive with either stock or anyclass -- A stock class is one either defined in the Haskell report or for which GHC -- otherwise knows how to generate code for (possibly requiring the use of a@@ -561,8 +560,7 @@ stock class to be able to be derived successfully. A class might be able to be used in a deriving clause if -XDeriveAnyClass-is willing to support it. The canDeriveAnyClass function checks if this is the-case.+is willing to support it. -} hasStockDeriving@@ -702,15 +700,16 @@ -- e.g. deriving( Eq s ) -- ...if not, try falling back on DeriveAnyClass.- | NotValid err <- canDeriveAnyClass dflags- = NonDerivableClass err -- Neither anyclass nor stock work+ | xopt LangExt.DeriveAnyClass dflags+ = CanDeriveAnyClass -- DeriveAnyClass should work | otherwise- = CanDeriveAnyClass -- DeriveAnyClass should work+ = NonDerivableClass -- Neither anyclass nor stock work -classArgsErr :: Class -> [Type] -> SDoc-classArgsErr cls cls_tys = quotes (ppr (mkClassPred cls cls_tys)) <+> text "is not a class" +classArgsErr :: Class -> [Type] -> DeriveInstanceErrReason+classArgsErr cls cls_tys = DerivErrNotAClass (mkClassPred cls cls_tys)+ -- Side conditions (whether the datatype must have at least one constructor, -- required language extensions, etc.) for using GHC's stock deriving -- mechanism on certain classes (as opposed to classes that require@@ -756,15 +755,6 @@ cond_vanilla = cond_stdOK deriv_ctxt True -- Vanilla data constructors but allow no data cons or polytype arguments -canDeriveAnyClass :: DynFlags -> Validity--- IsValid: we can (try to) derive it via an empty instance declaration--- NotValid s: we can't, reason s-canDeriveAnyClass dflags- | not (xopt LangExt.DeriveAnyClass dflags)- = NotValid (text "Try enabling DeriveAnyClass")- | otherwise- = IsValid -- OK!- type Condition = DynFlags @@ -774,17 +764,10 @@ -> TyCon -- ^ For data families, this is the representation 'TyCon'. -- Otherwise, this is the same as the other 'TyCon' argument. - -> Validity -- ^ 'IsValid' if deriving an instance for this 'TyCon' is- -- possible. Otherwise, it's @'NotValid' err@, where @err@- -- explains what went wrong.--orCond :: Condition -> Condition -> Condition-orCond c1 c2 dflags tc rep_tc- = case (c1 dflags tc rep_tc, c2 dflags tc rep_tc) of- (IsValid, _) -> IsValid -- c1 succeeds- (_, IsValid) -> IsValid -- c21 succeeds- (NotValid x, NotValid y) -> NotValid (x $$ text " or" $$ y)- -- Both fail+ -> Validity' DeriveInstanceErrReason+ -- ^ 'IsValid' if deriving an instance for this 'TyCon' is+ -- possible. Otherwise, it's @'NotValid' err@, where @err@+ -- explains what went wrong. andCond :: Condition -> Condition -> Condition andCond c1 c2 dflags tc rep_tc@@ -821,15 +804,14 @@ cond_stdOK deriv_ctxt permissive dflags tc rep_tc = valid_ADT `andValid` valid_misc where- valid_ADT, valid_misc :: Validity+ valid_ADT, valid_misc :: Validity' DeriveInstanceErrReason valid_ADT | isAlgTyCon tc || isDataFamilyTyCon tc = IsValid | otherwise -- Complain about functions, primitive types, and other tycons that -- stock deriving can't handle.- = NotValid $ text "The last argument of the instance must be a"- <+> text "data or newtype application"+ = NotValid DerivErrLastArgMustBeApp valid_misc = case deriv_ctxt of@@ -841,53 +823,63 @@ | null data_cons -- 1. , not permissive -> checkFlag LangExt.EmptyDataDeriving dflags tc rep_tc `orValid`- NotValid (no_cons_why rep_tc $$ empty_data_suggestion)+ NotValid (no_cons_why rep_tc) | not (null con_whys)- -> NotValid (vcat con_whys $$ possible_fix_suggestion wildcard)+ -> NotValid $ DerivErrBadConstructor (Just $ has_wildcard wildcard) con_whys | otherwise -> IsValid - empty_data_suggestion =- text "Use EmptyDataDeriving to enable deriving for empty data types"- possible_fix_suggestion wildcard+ has_wildcard wildcard = case wildcard of- Just _ ->- text "Possible fix: fill in the wildcard constraint yourself"- Nothing ->- text "Possible fix: use a standalone deriving declaration instead"+ Just _ -> YesHasWildcard+ Nothing -> NoHasWildcard data_cons = tyConDataCons rep_tc con_whys = getInvalids (map check_con data_cons) - check_con :: DataCon -> Validity+ check_con :: DataCon -> Validity' DeriveInstanceBadConstructor check_con con | not (null eq_spec) -- 2.- = bad "is a GADT"+ = bad DerivErrBadConIsGADT | not (null ex_tvs) -- 3.- = bad "has existential type variables in its type"+ = bad DerivErrBadConHasExistentials | not (null theta) -- 4.- = bad "has constraints in its type"+ = bad DerivErrBadConHasConstraints | not (permissive || all isTauTy (map scaledThing $ dataConOrigArgTys con)) -- 5.- = bad "has a higher-rank type"+ = bad DerivErrBadConHasHigherRankType | otherwise = IsValid where (_, ex_tvs, eq_spec, theta, _, _) = dataConFullSig con- bad msg = NotValid (badCon con (text msg))+ bad mkErr = NotValid $ mkErr con -no_cons_why :: TyCon -> SDoc-no_cons_why rep_tc = quotes (pprSourceTyCon rep_tc) <+>- text "must have at least one data constructor"+no_cons_why :: TyCon -> DeriveInstanceErrReason+no_cons_why = DerivErrNoConstructors cond_RepresentableOk :: Condition-cond_RepresentableOk _ _ rep_tc = canDoGenerics rep_tc+cond_RepresentableOk _ _ rep_tc =+ case canDoGenerics rep_tc of+ IsValid -> IsValid+ NotValid generic_errs -> NotValid $ DerivErrGenerics generic_errs cond_Representable1Ok :: Condition-cond_Representable1Ok _ _ rep_tc = canDoGenerics1 rep_tc+cond_Representable1Ok _ _ rep_tc =+ case canDoGenerics1 rep_tc of+ IsValid -> IsValid+ NotValid generic_errs -> NotValid $ DerivErrGenerics generic_errs cond_enumOrProduct :: Class -> Condition cond_enumOrProduct cls = cond_isEnumeration `orCond` (cond_isProduct `andCond` cond_args cls)+ where+ orCond :: Condition -> Condition -> Condition+ orCond c1 c2 dflags tc rep_tc+ = case (c1 dflags tc rep_tc, c2 dflags tc rep_tc) of+ (IsValid, _) -> IsValid -- c1 succeeds+ (_, IsValid) -> IsValid -- c21 succeeds+ (NotValid x, NotValid y) -> NotValid $ DerivErrEnumOrProduct x y+ -- Both fail + cond_args :: Class -> Condition -- ^ For some classes (eg 'Eq', 'Ord') we allow unlifted arg types -- by generating specialised code. For others (eg 'Data') we don't.@@ -896,8 +888,7 @@ cond_args cls _ _ rep_tc = case bad_args of [] -> IsValid- (ty:_) -> NotValid (hang (text "Don't know how to derive" <+> quotes (ppr cls))- 2 (text "for type" <+> quotes (ppr ty)))+ (ty:_) -> NotValid $ DerivErrDunnoHowToDeriveForType ty where bad_args = [ arg_ty | con <- tyConDataCons rep_tc , Scaled _ arg_ty <- dataConOrigArgTys con@@ -919,20 +910,14 @@ cond_isEnumeration :: Condition cond_isEnumeration _ _ rep_tc | isEnumerationTyCon rep_tc = IsValid- | otherwise = NotValid why- where- why = sep [ quotes (pprSourceTyCon rep_tc) <+>- text "must be an enumeration type"- , text "(an enumeration consists of one or more nullary, non-GADT constructors)" ]- -- See Note [Enumeration types] in GHC.Core.TyCon+ | otherwise = NotValid $ DerivErrMustBeEnumType rep_tc cond_isProduct :: Condition cond_isProduct _ _ rep_tc- | Just _ <- tyConSingleDataCon_maybe rep_tc = IsValid- | otherwise = NotValid why- where- why = quotes (pprSourceTyCon rep_tc) <+>- text "must have precisely one constructor"+ | Just _ <- tyConSingleDataCon_maybe rep_tc+ = IsValid+ | otherwise+ = NotValid $ DerivErrMustHaveExactlyOneConstructor rep_tc cond_functorOK :: Bool -> Bool -> Condition -- OK for Functor/Foldable/Traversable class@@ -943,12 +928,10 @@ -- (e) no "stupid context" on data type cond_functorOK allowFunctions allowExQuantifiedLastTyVar _ _ rep_tc | null tc_tvs- = NotValid (text "Data type" <+> quotes (ppr rep_tc)- <+> text "must have some type parameters")+ = NotValid $ DerivErrMustHaveSomeParameters rep_tc | not (null bad_stupid_theta)- = NotValid (text "Data type" <+> quotes (ppr rep_tc)- <+> text "must not have a class context:" <+> pprTheta bad_stupid_theta)+ = NotValid $ DerivErrMustNotHaveClassContext rep_tc bad_stupid_theta | otherwise = allValid (map check_con data_cons)@@ -962,7 +945,7 @@ data_cons = tyConDataCons rep_tc check_con con = allValid (check_universal con : foldDataConArgs (ft_check con) con) - check_universal :: DataCon -> Validity+ check_universal :: DataCon -> Validity' DeriveInstanceErrReason check_universal con | allowExQuantifiedLastTyVar = IsValid -- See Note [DeriveFoldable with ExistentialQuantification]@@ -972,31 +955,26 @@ , not (tv `elemVarSet` exactTyCoVarsOfTypes (dataConTheta con)) = IsValid -- See Note [Check that the type variable is truly universal] | otherwise- = NotValid (badCon con existential)+ = NotValid $ DerivErrBadConstructor Nothing [DerivErrBadConExistential con] - ft_check :: DataCon -> FFoldType Validity+ ft_check :: DataCon -> FFoldType (Validity' DeriveInstanceErrReason) ft_check con = FT { ft_triv = IsValid, ft_var = IsValid- , ft_co_var = NotValid (badCon con covariant)+ , ft_co_var = NotValid $ DerivErrBadConstructor Nothing [DerivErrBadConCovariant con] , ft_fun = \x y -> if allowFunctions then x `andValid` y- else NotValid (badCon con functions)+ else NotValid $ DerivErrBadConstructor Nothing [DerivErrBadConFunTypes con] , ft_tup = \_ xs -> allValid xs , ft_ty_app = \_ _ x -> x- , ft_bad_app = NotValid (badCon con wrong_arg)+ , ft_bad_app = NotValid $ DerivErrBadConstructor Nothing [DerivErrBadConWrongArg con] , ft_forall = \_ x -> x } - existential = text "must be truly polymorphic in the last argument of the data type"- covariant = text "must not use the type variable in a function argument"- functions = text "must not contain function types"- wrong_arg = text "must use the type variable only as the last argument of a data type" checkFlag :: LangExt.Extension -> Condition checkFlag flag dflags _ _ | xopt flag dflags = IsValid | otherwise = NotValid why where- why = text "You need " <> text flag_str- <+> text "to derive an instance for this class"- flag_str = case [ flagSpecName f | f <- xFlags , flagSpecFlag f == flag ] of+ why = DerivErrLangExtRequired the_flag+ the_flag = case [ flagSpecFlag f | f <- xFlags , flagSpecFlag f == flag ] of [s] -> s other -> pprPanic "checkFlag" (ppr other) @@ -1020,9 +998,6 @@ = classKey cls `elem` ([ readClassKey, showClassKey, dataClassKey , genClassKey, gen1ClassKey, typeableClassKey , traversableClassKey, liftClassKey ])--badCon :: DataCon -> SDoc -> SDoc-badCon con msg = text "Constructor" <+> quotes (ppr con) <+> msg ------------------------------------------------------------------
compiler/GHC/Tc/Errors.hs view
@@ -46,19 +46,21 @@ import GHC.Types.SrcLoc import GHC.Types.Basic import GHC.Types.Error+import GHC.Types.Unique.Set ( nonDetEltsUniqSet ) import GHC.Rename.Unbound ( unknownNameSuggestions, WhatLooking(..) ) import GHC.Unit.Module import GHC.Hs.Binds ( PatSynBind(..) )-import GHC.Builtin.Names ( typeableClassName )+import GHC.Builtin.Names ( typeableClassName, pretendNameIsInScope ) import qualified GHC.LanguageExtensions as LangExt import GHC.Core.Predicate import GHC.Core.Type import GHC.Core.Coercion import GHC.Core.TyCo.Rep-import GHC.Core.TyCo.Ppr ( pprTyVars, pprWithExplicitKindsWhen, pprSourceTyCon, pprWithTYPE )-import GHC.Core.Unify ( tcMatchTys, flattenTys )+import GHC.Core.TyCo.Ppr ( pprTyVars, pprWithExplicitKindsWhen, pprSourceTyCon+ , pprWithTYPE )+import GHC.Core.Unify ( tcMatchTys ) import GHC.Core.InstEnv import GHC.Core.TyCon import GHC.Core.Class@@ -75,12 +77,14 @@ import GHC.Data.Bag import GHC.Data.FastString import GHC.Utils.Trace (pprTraceUserWarning)-import GHC.Data.List.SetOps ( equivClasses )+import GHC.Data.List.SetOps ( equivClasses, nubOrdBy ) import GHC.Data.Maybe import qualified GHC.Data.Strict as Strict import Control.Monad ( unless, when, foldM, forM_ ) import Data.Foldable ( toList )+import Data.Functor ( (<&>) )+import Data.Function ( on ) import Data.List ( partition, mapAccumL, sortBy, unfoldr ) -- import Data.Semigroup ( Semigroup ) import qualified Data.Semigroup as Semigroup@@ -564,7 +568,10 @@ -- says to suppress ; let ctxt2 = ctxt { cec_suppress = cec_suppress ctxt || cec_suppress ctxt1 } ; (_, leftovers) <- tryReporters ctxt2 report2 cts1- ; massertPpr (null leftovers) (ppr leftovers)+ ; massertPpr (null leftovers)+ (text "The following unsolved Wanted constraints \+ \have not been reported to the user:"+ $$ ppr leftovers) -- All the Derived ones have been filtered out of simples -- by the constraint solver. This is ok; we don't want@@ -606,6 +613,7 @@ -- report2: we suppress these if there are insolubles elsewhere in the tree report2 = [ ("Implicit params", is_ip, False, mkGroupReporter mkIPErr) , ("Irreds", is_irred, False, mkGroupReporter mkIrredErr)+ , ("FixedRuntimeRep", is_FRR, False, mkGroupReporter mkFRRErr) , ("Dicts", is_dict, False, mkGroupReporter mkDictErr) ] -- also checks to make sure the constraint isn't HoleBlockerReason@@ -615,7 +623,7 @@ unblocked checker ct pred = checker ct pred -- rigid_nom_eq, rigid_nom_tv_eq,- is_dict, is_equality, is_ip, is_irred :: Ct -> Pred -> Bool+ is_dict, is_equality, is_ip, is_FRR, is_irred :: Ct -> Pred -> Bool is_given_eq ct pred | EqPred {} <- pred = arisesFromGivens ct@@ -652,6 +660,12 @@ is_ip _ (ClassPred cls _) = isIPClass cls is_ip _ _ = False + is_FRR ct (SpecialPred ConcretePrimPred _)+ | FixedRuntimeRepOrigin {} <- ctOrigin ct+ = True+ is_FRR _ _+ = False+ is_irred _ (IrredPred {}) = True is_irred _ _ = False @@ -928,9 +942,10 @@ -- See Note [No deferring for multiplicity errors] nonDeferrableOrigin :: CtOrigin -> Bool-nonDeferrableOrigin NonLinearPatternOrigin = True-nonDeferrableOrigin (UsageEnvironmentOf _) = True-nonDeferrableOrigin _ = False+nonDeferrableOrigin NonLinearPatternOrigin = True+nonDeferrableOrigin (UsageEnvironmentOf {}) = True+nonDeferrableOrigin (FixedRuntimeRepOrigin {}) = True+nonDeferrableOrigin _ = False maybeReportError :: ReportErrCtxt -> Ct -> Report -> TcM () maybeReportError ctxt ct report@@ -1428,6 +1443,53 @@ where (ct1:_) = cts +----------------++-- | Create a user-facing error message for unsolved @'Concrete#' ki@+-- Wanted constraints arising from representation-polymorphism checks.+--+-- See Note [Reporting representation-polymorphism errors] in GHC.Tc.Types.Origin.+mkFRRErr :: ReportErrCtxt -> [Ct] -> TcM Report+mkFRRErr ctxt cts+ = do { -- Zonking/tidying.+ ; origs <-+ -- Zonk/tidy the 'CtOrigin's.+ zonkTidyOrigins (cec_tidy ctxt) (map ctOrigin cts)+ <&>+ -- Then remove duplicates: only retain one 'CtOrigin' per representation-polymorphic type.+ (nubOrdBy (nonDetCmpType `on` frr_type) . snd)++ -- Obtain all the errors we want to report (constraints with FixedRuntimeRep origin),+ -- with the corresponding types:+ -- ty1 :: TYPE rep1, ty2 :: TYPE rep2, ...+ ; let tys = map frr_type origs+ kis = map typeKind tys++ -- Assemble the error message: pair up each origin with the corresponding type, e.g.+ -- • FixedRuntimeRep origin msg 1 ...+ -- a :: TYPE r1+ -- • FixedRuntimeRep origin msg 2 ...+ -- b :: TYPE r2++ combine_origin_ty_ki :: CtOrigin -> Type -> Kind -> SDoc+ combine_origin_ty_ki orig ty ki =+ -- Add bullet points if there is more than one error.+ (if length tys > 1 then (bullet <+>) else id) $+ vcat [pprArising orig <> colon+ ,nest 2 $ ppr ty <+> dcolon <+> pprWithTYPE ki]++ msg :: SDoc+ msg = vcat $ zipWith3 combine_origin_ty_ki origs tys kis++ ; return $ important msg }+ where++ frr_type :: CtOrigin -> Type+ frr_type (FixedRuntimeRepOrigin ty _) = ty+ frr_type orig+ = pprPanic "mkFRRErr: not a FixedRuntimeRep origin"+ (text "origin =" <+> ppr orig)+ {- Note [Constraints include ...] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@@ -2396,7 +2458,7 @@ ************************************************************************ -} -mkDictErr :: ReportErrCtxt -> [Ct] -> TcM Report+mkDictErr :: HasDebugCallStack => ReportErrCtxt -> [Ct] -> TcM Report mkDictErr ctxt cts = assert (not (null cts)) $ do { inst_envs <- tcGetInstEnvs@@ -2420,8 +2482,7 @@ && (null unifiers || all (not . isAmbiguousTyVar) (tyCoVarsOfCtList ct)) lookup_cls_inst inst_envs ct- -- Note [Flattening in error message generation]- = (ct, lookupInstEnv True inst_envs clas (flattenTys emptyInScopeSet tys))+ = (ct, lookupInstEnv True inst_envs clas tys) where (clas, tys) = getClassPredTys (ctPred ct) @@ -2431,7 +2492,18 @@ -- but we really only want to report the latter elim_superclasses cts = mkMinimalBySCs ctPred cts -mk_dict_err :: ReportErrCtxt -> (Ct, ClsInstLookupResult)+-- [Note: mk_dict_err]+-- ~~~~~~~~~~~~~~~~~~~+-- Different dictionary error messages are reported depending on the number of+-- matches and unifiers:+--+-- - No matches, regardless of unifiers: report "No instance for ...".+-- - Two or more matches, regardless of unifiers: report "Overlapping instances for ...",+-- and show the matching and unifying instances.+-- - One match, one or more unifiers: report "Overlapping instances for", show the+-- matching and unifying instances, and say "The choice depends on the instantion of ...,+-- and the result of evaluating ...".+mk_dict_err :: HasCallStack => ReportErrCtxt -> (Ct, ClsInstLookupResult) -> TcM SDoc -- Report an overlap error if this class constraint results -- from an overlap (returning Left clas), otherwise return (Right pred)@@ -2620,12 +2692,24 @@ , nest 2 (vcat (pp_givens useful_givens))] , ppWhen (isSingleton matches) $- parens (vcat [ text "The choice depends on the instantiation of" <+>- quotes (pprWithCommas ppr (tyCoVarsOfTypesList tys))+ parens (vcat [ ppUnless (null tyCoVars) $+ text "The choice depends on the instantiation of" <+>+ quotes (pprWithCommas ppr tyCoVars)+ , ppUnless (null famTyCons) $+ if (null tyCoVars)+ then+ text "The choice depends on the result of evaluating" <+>+ quotes (pprWithCommas ppr famTyCons)+ else+ text "and the result of evaluating" <+>+ quotes (pprWithCommas ppr famTyCons) , ppWhen (null (matching_givens)) $ vcat [ text "To pick the first instance above, use IncoherentInstances" , text "when compiling the other instance declarations"] ])]+ where+ tyCoVars = tyCoVarsOfTypesList tys+ famTyCons = filter isFamilyTyCon $ concatMap (nonDetEltsUniqSet . tyConsOfType) tys matching_givens = mapMaybe matchable useful_givens @@ -2862,8 +2946,8 @@ orphNamesOfTypes (is_tys cls_inst) name_in_scope name- | isBuiltInSyntax name- = True -- E.g. (->)+ | pretendNameIsInScope name+ = True -- E.g. (->); see Note [pretendNameIsInScope] in GHC.Builtin.Names | Just mod <- nameModule_maybe name = qual_in_scope (qualName sty mod (nameOccName name)) | otherwise@@ -2897,7 +2981,7 @@ These are the ones most likely to be useful to the programmer. * Show at most n_show in-scope instances,- and summarise the rest ("plus 3 others")+ and summarise the rest ("plus N others") * Summarise the not-in-scope instances ("plus 4 not in scope") @@ -2906,18 +2990,6 @@ -} {--Note [Flattening in error message generation]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Consider (C (Maybe (F x))), where F is a type function, and we have-instances- C (Maybe Int) and C (Maybe a)-Since (F x) might turn into Int, this is an overlap situation, and-indeed the main solver will have refrained-from solving. But by the time we get to error message generation, we've-un-flattened the constraint. So we must *re*-flatten it before looking-up in the instance environment, lest we only report one matching-instance when in fact there are two.- Note [Kind arguments in error messages] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It can be terribly confusing to get an error message like (#9171)@@ -3048,7 +3120,7 @@ -- enclosing *type* equality, because that's more useful for the programmer ; let extra_tvs = case tidy_orig of KindEqOrigin t1 t2 _ _ -> tyCoVarsOfTypes [t1,t2]- _ -> emptyVarSet+ _ -> emptyVarSet ct_fvs = tyCoVarsOfCt ct `unionVarSet` extra_tvs -- Put a zonked, tidied CtOrigin into the Ct@@ -3164,19 +3236,26 @@ text "use -fmax-relevant-binds=N or -fno-max-relevant-binds)" ------------------------warnDefaulting :: [Ct] -> Type -> TcM ()-warnDefaulting wanteds default_ty+warnDefaulting :: TcTyVar -> [Ct] -> Type -> TcM ()+warnDefaulting the_tv wanteds default_ty = do { warn_default <- woptM Opt_WarnTypeDefaults ; env0 <- tcInitTidyEnv ; let tidy_env = tidyFreeTyCoVars env0 $ tyCoVarsOfCtsList (listToBag wanteds) tidy_wanteds = map (tidyCt tidy_env) wanteds+ tidy_tv = lookupVarEnv (snd tidy_env) the_tv (loc, ppr_wanteds) = pprWithArising tidy_wanteds warn_msg =- hang (hsep [ text "Defaulting the following"- , text "constraint" <> plural tidy_wanteds- , text "to type"- , quotes (ppr default_ty) ])+ hang (hsep $ [ text "Defaulting" ]+ +++ (case tidy_tv of+ Nothing -> []+ Just tv -> [text "the type variable"+ , quotes (ppr tv)])+ +++ [ text "to type"+ , quotes (ppr default_ty)+ , text "in the following constraint" <> plural tidy_wanteds ]) 2 ppr_wanteds ; let diag = TcRnUnknownMessage $
compiler/GHC/Tc/Errors/Hole.hs view
@@ -66,7 +66,7 @@ import Data.Graph ( graphFromEdges, topSort ) -import GHC.Tc.Solver ( simplifyTopWanteds, runTcSDeriveds )+import GHC.Tc.Solver ( simplifyTopWanteds, runTcSDerivedsEarlyAbort ) import GHC.Tc.Utils.Unify ( tcSubTypeSigma ) import GHC.HsToCore.Docs ( extractDocs )@@ -391,6 +391,26 @@ would cause the type checker to error, it is not a valid hole fit, and thus it is discarded. +Note [Speeding up valid hole-fits]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+To fix #16875 we noted that a lot of time was being spent on uneccessary work.++When we'd call `tcCheckHoleFit hole hole_ty ty`, we would end up by generating+a constraint to show that `hole_ty ~ ty`, including any constraints in `ty`. For+example, if `hole_ty = Int` and `ty = Foldable t => (a -> Bool) -> t a -> Bool`,+we'd have `(a_a1pa[sk:1] -> Bool) -> t_t2jk[sk:1] a_a1pa[sk:1] -> Bool ~# Int`+from the coercion, as well as `Foldable t_t2jk[sk:1]`. By adding a flag to+`TcSEnv` and adding a `runTcSDerivedsEarlyAbort`, we can fail as soon as we hit+an insoluble constraint. Since we don't need the result in the case that it+fails, a boolean `False` (i.e. "it didn't work" from `runTcSDerivedsEarlyAbort`)+is sufficient.++We also check whether the type of the hole is an immutable type variable (i.e.+a skolem). In that case, the only possible fits are fits of exactly that type,+which can only come from the locals. This speeds things up quite a bit when we+don't know anything about the type of the hole. This also helps with degenerate+fits like (`id (_ :: a)` and `head (_ :: [a])`) when looking for fits of type+`a`, where `a` is a skolem. -} data HoleFitDispConfig = HFDC { showWrap :: Bool@@ -574,7 +594,11 @@ map IdHFCand lclBinds ++ map GreHFCand lcl globals = map GreHFCand gbl syntax = map NameHFCand builtIns- to_check = locals ++ syntax ++ globals+ -- If the hole is a rigid type-variable, then we only check the+ -- locals, since only they can match the type (in a meaningful way).+ only_locals = any isImmutableTyVar $ getTyVar_maybe hole_ty+ to_check = if only_locals then locals+ else locals ++ syntax ++ globals ; cands <- foldM (flip ($)) to_check candidatePlugins ; traceTc "numPlugins are:" $ ppr (length candidatePlugins) ; (searchDiscards, subs) <-@@ -876,7 +900,6 @@ ; traceTc "Did it fit?" $ ppr fits ; traceTc "wrap is: " $ ppr wrp ; traceTc "checkingFitOf }" empty- ; z_wrp_tys <- zonkTcTypes (unfoldWrapper wrp) -- We'd like to avoid refinement suggestions like `id _ _` or -- `head _ _`, and only suggest refinements where our all phantom -- variables got unified during the checking. This can be disabled@@ -885,24 +908,26 @@ -- variables, i.e. zonk them to read their final value to check for -- abstract refinements, and to report what the type of the simulated -- holes must be for this to be a match.- ; if fits- then if null ref_vars- then return (Just (z_wrp_tys, []))- else do { let -- To be concrete matches, matches have to- -- be more than just an invented type variable.- fvSet = fvVarSet fvs- notAbstract :: TcType -> Bool- notAbstract t = case getTyVar_maybe t of- Just tv -> tv `elemVarSet` fvSet- _ -> True- allConcrete = all notAbstract z_wrp_tys- ; z_vars <- zonkTcTyVars ref_vars- ; let z_mtvs = mapMaybe tcGetTyVar_maybe z_vars- ; allFilled <- not <$> anyM isFlexiTyVar z_mtvs- ; allowAbstract <- goptM Opt_AbstractRefHoleFits- ; if allowAbstract || (allFilled && allConcrete )- then return $ Just (z_wrp_tys, z_vars)- else return Nothing }+ ; if fits then do {+ -- Zonking is expensive, so we only do it if required.+ z_wrp_tys <- zonkTcTypes (unfoldWrapper wrp)+ ; if null ref_vars+ then return (Just (z_wrp_tys, []))+ else do { let -- To be concrete matches, matches have to+ -- be more than just an invented type variable.+ fvSet = fvVarSet fvs+ notAbstract :: TcType -> Bool+ notAbstract t = case getTyVar_maybe t of+ Just tv -> tv `elemVarSet` fvSet+ _ -> True+ allConcrete = all notAbstract z_wrp_tys+ ; z_vars <- zonkTcTyVars ref_vars+ ; let z_mtvs = mapMaybe tcGetTyVar_maybe z_vars+ ; allFilled <- not <$> anyM isFlexiTyVar z_mtvs+ ; allowAbstract <- goptM Opt_AbstractRefHoleFits+ ; if allowAbstract || (allFilled && allConcrete )+ then return $ Just (z_wrp_tys, z_vars)+ else return Nothing }} else return Nothing } where fvs = mkFVs ref_vars `unionFV` hole_fvs `unionFV` tyCoFVsOfType ty hole = typed_hole { th_hole = Nothing }@@ -942,7 +967,8 @@ -- constraints on the type of the hole. tcCheckHoleFit :: TypedHole -- ^ The hole to check against -> TcSigmaType- -- ^ The type to check against (possibly modified, e.g. refined)+ -- ^ The type of the hole to check against (possibly modified,+ -- e.g. refined with additional holes for refinement hole-fits.) -> TcSigmaType -- ^ The type to check whether fits. -> TcM (Bool, HsWrapper) -- ^ Whether it was a match, and the wrapper from hole_ty to ty.@@ -970,22 +996,21 @@ -- The relevant constraints may contain HoleDests, so we must -- take care to clone them as well (to avoid #15370). ; cloned_relevants <- mapBagM cloneWanted th_relevant_cts- -- We wrap the WC in the nested implications, see+ -- We wrap the WC in the nested implications, for details, see -- Note [Checking hole fits]- ; let outermost_first = reverse th_implics- -- We add the cloned relevants to the wanteds generated by- -- the call to tcSubType_NC, see Note [Relevant constraints]- -- There's no need to clone the wanteds, because they are- -- freshly generated by `tcSubtype_NC`.- w_rel_cts = addSimples wanted cloned_relevants- final_wc = foldr (setWCAndBinds fresh_binds) w_rel_cts outermost_first+ ; let wrapInImpls cts = foldl (flip (setWCAndBinds fresh_binds)) cts th_implics+ final_wc = wrapInImpls $ addSimples wanted cloned_relevants+ -- We add the cloned relevants to the wanteds generated+ -- by the call to tcSubType_NC, for details, see+ -- Note [Relevant constraints]. There's no need to clone+ -- the wanteds, because they are freshly generated by the+ -- call to`tcSubtype_NC`. ; traceTc "final_wc is: " $ ppr final_wc- ; rem <- runTcSDeriveds $ simplifyTopWanteds final_wc- -- We don't want any insoluble or simple constraints left, but- -- solved implications are ok (and necessary for e.g. undefined)- ; traceTc "rems was:" $ ppr rem+ -- See Note [Speeding up valid-hole fits]+ ; (rem, _) <- tryTc $ runTcSDerivedsEarlyAbort $ simplifyTopWanteds final_wc ; traceTc "}" empty- ; return (isSolvedWC rem, wrap) } }+ ; return (any isSolvedWC rem, wrap)+ } } where setWCAndBinds :: EvBindsVar -- Fresh ev binds var. -> Implication -- The implication to put WC in.
compiler/GHC/Tc/Gen/App.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} -- Wrinkle in Note [Trees That Grow]@@ -21,13 +22,21 @@ import {-# SOURCE #-} GHC.Tc.Gen.Expr( tcPolyExpr ) -import GHC.Builtin.Types (multiplicityTy)+import GHC.Types.Basic ( Arity )+import GHC.Types.Id ( idArity, idName, hasNoBinding )+import GHC.Types.Name ( isWiredInName )+import GHC.Types.Var+import GHC.Builtin.Types ( multiplicityTy )+import GHC.Core.ConLike ( ConLike(..) )+import GHC.Core.DataCon ( dataConRepArity+ , isNewDataCon, isUnboxedSumDataCon, isUnboxedTupleDataCon ) import GHC.Tc.Gen.Head import GHC.Hs import GHC.Tc.Errors.Types import GHC.Tc.Utils.Monad import GHC.Tc.Utils.Unify import GHC.Tc.Utils.Instantiate+import GHC.Tc.Utils.Concrete ( hasFixedRuntimeRep ) import GHC.Tc.Instance.Family ( tcGetFamInstEnvs, tcLookupDataFamInst_maybe ) import GHC.Tc.Gen.HsType import GHC.Tc.Utils.TcMType@@ -317,6 +326,22 @@ ; do_ql <- wantQuickLook rn_fun ; (delta, inst_args, app_res_rho) <- tcInstFun do_ql True fun fun_sigma rn_args + -- Check for representation polymorphism in the case that+ -- the head of the application is a primop or data constructor+ -- which has argument types that are representation-polymorphic.+ -- This amounts to checking that the leftover argument types,+ -- up until the arity, are not representation-polymorphic,+ -- so that we can perform eta-expansion later without introducing+ -- representation-polymorphic binders.+ --+ -- See Note [Checking for representation-polymorphic built-ins]+ ; traceTc "tcApp FRR" $+ vcat+ [ text "tc_fun =" <+> ppr tc_fun+ , text "inst_args =" <+> ppr inst_args+ , text "app_res_rho =" <+> ppr app_res_rho ]+ ; hasFixedRuntimeRep_remainingValArgs inst_args app_res_rho tc_fun+ -- Quick look at result ; app_res_rho <- if do_ql then quickLookResultType delta app_res_rho exp_res_ty@@ -353,14 +378,221 @@ -- Typecheck the value arguments ; tc_args <- tcValArgs do_ql inst_args - -- Reconstruct, with special case for tagToEnum#- ; tc_expr <- if isTagToEnum rn_fun- then tcTagToEnum tc_fun fun_ctxt tc_args app_res_rho- else return (rebuildHsApps tc_fun fun_ctxt tc_args)+ -- Reconstruct, with a special cases for tagToEnum#.+ ; tc_expr <-+ if isTagToEnum rn_fun+ then tcTagToEnum tc_fun fun_ctxt tc_args app_res_rho+ else do return (rebuildHsApps tc_fun fun_ctxt tc_args) -- Wrap the result ; return (mkHsWrapCo res_co tc_expr) } +{-+Note [Checking for representation-polymorphic built-ins]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We cannot have representation-polymorphic or levity-polymorphic+function arguments. See Note [Representation polymorphism invariants]+in GHC.Core. That is checked by the calls to `hasFixedRuntimeRep ` in+`tcEValArg`.++But some /built-in/ functions are representation-polymorphic. Users+can't define such Ids; they are all GHC built-ins or data+constructors. Specifically they are:++1. A few wired-in Ids like unsafeCoerce#, with compulsory unfoldings.+2. Primops, such as raise#+3. Newtype constructors with `UnliftedNewtypes` that have+ a representation-polymorphic argument.+4. Representation-polymorphic data constructors: unboxed tuples+ and unboxed sums.++For (1) consider+ badId :: forall r (a :: TYPE r). a -> a+ badId = unsafeCoerce# @r @r @a @a++The wired-in function+ unsafeCoerce# :: forall (r1 :: RuntimeRep) (r2 :: RuntimeRep)+ (a :: TYPE r1) (b :: TYPE r2).+ a -> b+has a convenient but representation-polymorphic type. It has no+binding; instead it has a compulsory unfolding, after which we+would have+ badId = /\r /\(a :: TYPE r). \(x::a). ...body of unsafeCorece#...+And this is no good because of that rep-poly \(x::a). So we want+to reject this.++On the other hand+ goodId :: forall (a :: Type). a -> a+ goodId = unsafeCoerce# @LiftedRep @LiftedRep @a @a++is absolutely fine, because after we inline the unfolding, the \(x::a)+is representation-monomorphic.++Test cases: T14561, RepPolyWrappedVar2.++For primops (2) the situation is similar; they are eta-expanded in+CorePrep to be saturated, and that eta-expansion must not add a+representation-polymorphic lambda.++Test cases: T14561b, RepPolyWrappedVar, UnliftedNewtypesCoerceFail.++For (3), consider a representation-polymorphic newtype with+UnliftedNewtypes:++ type Id :: forall r. TYPE r -> TYPE r+ newtype Id a where { MkId :: a }++ bad :: forall r (a :: TYPE r). a -> Id a+ bad = MkId @r @a -- Want to reject++ good :: forall (a :: Type). a -> Id a+ good = MkId @LiftedRep @a -- Want to accept++Test cases: T18481, UnliftedNewtypesLevityBinder++So these three cases need special treatment. We add a special case+in tcApp to check whether an application of an Id has any remaining+representation-polymorphic arguments, after instantiation and application+of previous arguments. This is achieved by the hasFixedRuntimeRep_remainingValArgs+function, which computes the types of the remaining value arguments, and checks+that each of these have a fixed runtime representation using hasFixedRuntimeRep.++Wrinkles++* Because of Note [Typechecking data constructors] in GHC.Tc.Gen.Head,+ we desugar a representation-polymorphic data constructor application+ like this:+ (/\(r :: RuntimeRep) (a :: TYPE r) \(x::a). K r a x) @LiftedRep Int 4+ That is, a rep-poly lambda applied to arguments that instantiate it in+ a rep-mono way. It's a bit like a compulsory unfolding that has been+ inlined, but not yet beta-reduced.++ Because we want to accept this, we switch off Lint's representation+ polymorphism checks when Lint checks the output of the desugarer;+ see the lf_check_fixed_repy flag in GHC.Core.Lint.lintCoreBindings.++* Arity. We don't want to check for arguments past the+ arity of the function. For example++ raise# :: forall {r :: RuntimeRep} (a :: Type) (b :: TYPE r). a -> b++ has arity 1, so an instantiation such as:++ foo :: forall w r (z :: TYPE r). w -> z -> z+ foo = raise# @w @(z -> z)++ is unproblematic. This means we must take care not to perform a+ representation-polymorphism check on `z`.++ To achieve this, we consult the arity of the 'Id' which is the head+ of the application (or just use 1 for a newtype constructor),+ and keep track of how many value-level arguments we have seen,+ to ensure we stop checking once we reach the arity.+ This is slightly complicated by the need to include both visible+ and invisible arguments, as the arity counts both:+ see GHC.Tc.Gen.Head.countVisAndInvisValArgs.++ Test cases: T20330{a,b}++-}++-- | Check for representation-polymorphism in the remaining argument types+-- of a variable or data constructor, after it has been instantiated and applied to some arguments.+--+-- See Note [Checking for representation-polymorphic built-ins]+hasFixedRuntimeRep_remainingValArgs :: [HsExprArg 'TcpInst] -> TcRhoType -> HsExpr GhcTc -> TcM ()+hasFixedRuntimeRep_remainingValArgs applied_args app_res_rho = \case++ HsVar _ (L _ fun_id)++ -- (1): unsafeCoerce#+ -- 'unsafeCoerce#' is peculiar: it is patched in manually as per+ -- Note [Wiring in unsafeCoerce#] in GHC.HsToCore.+ -- Unfortunately, even though its arity is set to 1 in GHC.HsToCore.mkUnsafeCoercePrimPair,+ -- at this stage, if we query idArity, we get 0. This is because+ -- we end up looking at the non-patched version of unsafeCoerce#+ -- defined in Unsafe.Coerce, and that one indeed has arity 0.+ --+ -- We thus manually specify the correct arity of 1 here.+ | idName fun_id == unsafeCoercePrimName+ -> check_thing fun_id 1 (FRRNoBindingResArg fun_id)++ -- (2): primops and other wired-in representation-polymorphic functions,+ -- such as 'rightSection', 'oneShot', etc; see bindings with Compulsory unfoldings+ -- in GHC.Types.Id.Make+ | isWiredInName (idName fun_id) && hasNoBinding fun_id+ -> check_thing fun_id (idArity fun_id) (FRRNoBindingResArg fun_id)+ -- NB: idArity consults the IdInfo of the Id. This can be a problem+ -- in the presence of hs-boot files, as we might not have finished+ -- typechecking; inspecting the IdInfo at this point can cause+ -- strange Core Lint errors (see #20447).+ -- We avoid this entirely by only checking wired-in names,+ -- as those are the only ones this check is applicable to anyway.+++ XExpr (ConLikeTc (RealDataCon con) _ _)+ -- (3): Representation-polymorphic newtype constructors.+ | isNewDataCon con+ -- (4): Unboxed tuples and unboxed sums+ || isUnboxedTupleDataCon con+ || isUnboxedSumDataCon con+ -> check_thing con (dataConRepArity con) (FRRDataConArg con)++ _ -> return ()++ where+ nb_applied_vis_val_args :: Int+ nb_applied_vis_val_args = count isHsValArg applied_args++ nb_applied_val_args :: Int+ nb_applied_val_args = countVisAndInvisValArgs applied_args++ arg_tys :: [TyCoBinder]+ arg_tys = fst $ splitPiTys 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+ -- be at least the arity of the function.++ check_thing :: Outputable thing => thing -> Arity -> (Int -> FRROrigin) -> TcM ()+ check_thing thing arity mk_frr_orig = do+ traceTc "tcApp remainingValArgs check_thing" (debug_msg thing arity)+ go (nb_applied_vis_val_args + 1) (nb_applied_val_args + 1) arg_tys+ where+ go :: Int -- ^ visible value argument index+ -- (only used to report the argument position in error messages)+ -> Int -- ^ value argument index+ -- used to count up to the arity to ensure we don't check too many argument types+ -> [TyCoBinder]+ -> TcM ()+ go _ i_val _+ | i_val > arity+ = return ()+ go _ _ []+ -- Should never happen: it would mean that the arity is higher+ -- than the number of arguments apparent from the type+ = pprPanic "hasFixedRuntimeRep_remainingValArgs" (debug_msg thing arity)+ go i_visval !i_val (Anon af (Scaled _ arg_ty) : tys)+ = case af of+ InvisArg ->+ go i_visval (i_val + 1) tys+ VisArg -> do+ _concrete_ev <- hasFixedRuntimeRep (mk_frr_orig i_visval) arg_ty+ go (i_visval + 1) (i_val + 1) tys+ go i_visval i_val (_: tys)+ = go i_visval i_val tys++ -- A message containing all the relevant info, in case this functions+ -- needs to be debugged again at some point.+ debug_msg :: Outputable thing => thing -> Arity -> SDoc+ debug_msg thing arity =+ vcat+ [ text "thing =" <+> ppr thing+ , text "arity =" <+> ppr arity+ , text "applied_args =" <+> ppr applied_args+ , text "nb_applied_vis_val_args =" <+> ppr nb_applied_vis_val_args+ , text "nb_applied_val_args =" <+> ppr nb_applied_val_args+ , text "arg_tys =" <+> ppr arg_tys ]+ -------------------- wantQuickLook :: HsExpr GhcRn -> TcM Bool -- GHC switches on impredicativity all the time for ($)@@ -438,9 +670,10 @@ tcEValArg ctxt (ValArg larg@(L arg_loc arg)) exp_arg_sigma = addArgCtxt ctxt larg $ do { arg' <- tcPolyExpr arg (mkCheckExpType exp_arg_sigma)+ ; _concrete_ev <- hasFixedRuntimeRep (FRRApp arg) exp_arg_sigma ; return (L arg_loc arg') } -tcEValArg ctxt (ValArgQL { va_expr = larg@(L arg_loc _)+tcEValArg ctxt (ValArgQL { va_expr = larg@(L arg_loc arg) , va_fun = (inner_fun, fun_ctxt) , va_args = inner_args , va_ty = app_res_rho }) exp_arg_sigma@@ -448,6 +681,7 @@ do { traceTc "tcEValArgQL {" (vcat [ ppr inner_fun <+> ppr inner_args ]) ; tc_args <- tcValArgs True inner_args ; co <- unifyType Nothing app_res_rho exp_arg_sigma+ ; _concrete_ev <- hasFixedRuntimeRep (FRRApp arg) exp_arg_sigma ; traceTc "tcEValArg }" empty ; return (L arg_loc $ mkHsWrapCo co $ rebuildHsApps inner_fun fun_ctxt tc_args) }
compiler/GHC/Tc/Gen/Arrow.hs view
@@ -22,6 +22,7 @@ import GHC.Tc.Errors.Types import GHC.Tc.Gen.Match import GHC.Tc.Gen.Head( tcCheckId )+import GHC.Tc.Utils.Concrete ( hasFixedRuntimeRep ) import GHC.Tc.Utils.TcType import GHC.Tc.Utils.TcMType import GHC.Tc.Gen.Bind@@ -91,16 +92,17 @@ -> ExpRhoType -- Expected type of whole proc expression -> TcM (LPat GhcTc, LHsCmdTop GhcTc, TcCoercion) -tcProc pat cmd@(L _ (HsCmdTop names _)) exp_ty+tcProc pat cmd@(L loc (HsCmdTop names _)) exp_ty = do { exp_ty <- expTypeToType exp_ty -- no higher-rank stuff with arrows ; (co, (exp_ty1, res_ty)) <- matchExpectedAppTy exp_ty ; (co1, (arr_ty, arg_ty)) <- matchExpectedAppTy exp_ty1 -- start with the names as they are used to desugar the proc itself -- See #17423- ; names' <- mapM (tcSyntaxName ProcOrigin arr_ty) names+ ; names' <- setSrcSpan loc $+ mapM (tcSyntaxName ProcOrigin arr_ty) names ; let cmd_env = CmdEnv { cmd_arr = arr_ty } ; (pat', cmd') <- newArrowScope- $ tcCheckPat ProcExpr pat (unrestricted arg_ty)+ $ 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))@@ -141,9 +143,10 @@ ---------------------------------------- tcCmd :: CmdEnv -> LHsCmd GhcRn -> CmdType -> TcM (LHsCmd GhcTc) -- The main recursive function-tcCmd env (L loc cmd) res_ty+tcCmd env (L loc cmd) cmd_ty@(_, res_ty) = setSrcSpan (locA loc) $ do- { cmd' <- tc_cmd env cmd res_ty+ { cmd' <- tc_cmd env cmd cmd_ty+ ; _concrete_ev <- hasFixedRuntimeRep (FRRArrow $ ArrowCmdResTy cmd) res_ty ; return (L loc cmd') } tc_cmd :: CmdEnv -> HsCmd GhcRn -> CmdType -> TcM (HsCmd GhcTc)@@ -219,6 +222,10 @@ ; arg' <- tcCheckMonoExpr arg arg_ty + ; _concrete_ev <- hasFixedRuntimeRep+ (FRRArrow $ ArrowCmdArrApp (unLoc fun) (unLoc arg) ho_app)+ fun_ty+ ; return (HsCmdArrApp fun_ty fun' arg' ho_app lr) } where -- Before type-checking f, use the environment of the enclosing@@ -243,6 +250,9 @@ do { arg_ty <- newOpenFlexiTyVarTy ; fun' <- tcCmd env fun (mkPairTy arg_ty cmd_stk, res_ty) ; arg' <- tcCheckMonoExpr arg arg_ty+ ; _concrete_ev <- hasFixedRuntimeRep+ (FRRArrow $ ArrowCmdApp (unLoc fun) (unLoc arg))+ arg_ty ; return (HsCmdApp x fun' arg') } -------------------------------------------@@ -262,20 +272,31 @@ -- Check the patterns, and the GRHSs inside ; (pats', grhss') <- setSrcSpanA mtch_loc $- tcPats LambdaExpr pats (map (unrestricted . mkCheckExpType) arg_tys) $+ tcPats (ArrowMatchCtxt KappaExpr)+ pats (map (unrestricted . mkCheckExpType) arg_tys) $ tc_grhss grhss cmd_stk' (mkCheckExpType res_ty) ; let match' = L mtch_loc (Match { m_ext = noAnn- , m_ctxt = LambdaExpr, m_pats = pats'+ , m_ctxt = ArrowMatchCtxt KappaExpr+ , m_pats = pats' , m_grhss = grhss' }) arg_tys = map (unrestricted . hsLPatType) pats'++ ; _concrete_evs <-+ zipWithM+ (\ (Scaled _ arg_ty) i ->+ hasFixedRuntimeRep (FRRArrow $ ArrowCmdLam i) arg_ty)+ arg_tys+ [1..]++ ; let cmd' = HsCmdLam x (MG { mg_alts = L l [match'] , mg_ext = MatchGroupTc arg_tys res_ty , mg_origin = origin }) ; return (mkHsCmdWrap (mkWpCastN co) cmd') } where n_pats = length pats- match_ctxt = LambdaExpr -- Maybe KappaExpr?+ match_ctxt = ArrowMatchCtxt KappaExpr pg_ctxt = PatGuard match_ctxt tc_grhss (GRHSs x grhss binds) stk_ty res_ty@@ -324,11 +345,12 @@ where tc_cmd_arg :: LHsCmdTop GhcRn -> TcM (LHsCmdTop GhcTc, TcType)- tc_cmd_arg cmd@(L _ (HsCmdTop names _))+ tc_cmd_arg cmd@(L loc (HsCmdTop names _)) = do { arr_ty <- newFlexiTyVarTy arrowTyConKind ; stk_ty <- newFlexiTyVarTy liftedTypeKind ; res_ty <- newFlexiTyVarTy liftedTypeKind- ; names' <- mapM (tcSyntaxName ProcOrigin arr_ty) names+ ; names' <- setSrcSpan loc $+ mapM (tcSyntaxName ArrowCmdOrigin arr_ty) names ; let env' = env { cmd_arr = arr_ty } ; cmd' <- tcCmdTop env' names' cmd (stk_ty, res_ty) ; return (cmd', mkCmdArrTy env' (mkPairTy alphaTy stk_ty) res_ty) }@@ -350,7 +372,7 @@ tcCmdMatches env scrut_ty matches (stk, res_ty) = tcMatchesCase match_ctxt (unrestricted scrut_ty) matches (mkCheckExpType res_ty) where- match_ctxt = MC { mc_what = CaseAlt,+ match_ctxt = MC { mc_what = ArrowMatchCtxt ArrowCaseAlt, mc_body = mc_body } mc_body body res_ty' = do { res_ty' <- expTypeToType res_ty' ; tcCmd env body (stk, res_ty') }
compiler/GHC/Tc/Gen/Bind.hs view
@@ -34,6 +34,7 @@ import GHC.Hs import GHC.Tc.Errors.Types import GHC.Tc.Gen.Sig+import GHC.Tc.Utils.Concrete ( hasFixedRuntimeRep ) import GHC.Tc.Utils.Monad import GHC.Tc.Types.Origin import GHC.Tc.Utils.Env@@ -519,6 +520,11 @@ InferGen mn -> tcPolyInfer rec_tc prag_fn sig_fn mn bind_list CheckGen lbind sig -> tcPolyCheck prag_fn sig lbind + ; _concrete_evs <-+ mapM (\ poly_id ->+ hasFixedRuntimeRep (FRRBinder $ idName poly_id) (idType poly_id))+ poly_ids+ ; traceTc "} End of bindings for" (vcat [ ppr binder_names, ppr rec_group , vcat [ppr id <+> ppr (idType id) | id <- poly_ids] ])@@ -1181,7 +1187,7 @@ -> [LHsBind GhcRn] -> TcM (LHsBinds GhcTc, [MonoBindInfo]) --- SPECIAL CASE 1: see Note [Inference for non-recursive function bindings]+-- SPECIAL CASE 1: see Note [Special case for non-recursive function bindings] tcMonoBinds is_rec sig_fn no_gen [ L b_loc (FunBind { fun_id = L nm_loc name , fun_matches = matches })]@@ -1210,7 +1216,7 @@ , mbi_sig = Nothing , mbi_mono_id = mono_id }]) } --- SPECIAL CASE 2: see Note [Inference for non-recursive pattern bindings]+-- SPECIAL CASE 2: see Note [Special case for non-recursive pattern bindings] tcMonoBinds is_rec sig_fn no_gen [L b_loc (PatBind { pat_lhs = pat, pat_rhs = grhss })] | NonRecursive <- is_rec -- ...binder isn't mentioned in RHS@@ -1470,6 +1476,7 @@ do { traceTc "tcRhs: pat bind" (ppr pat' $$ ppr pat_ty) ; grhss' <- addErrCtxt (patMonoBindsCtxt pat' grhss) $ tcGRHSsPat grhss (mkCheckExpType pat_ty)+ ; return ( PatBind { pat_lhs = pat', pat_rhs = grhss' , pat_ext = pat_ty , pat_ticks = ([],[]) } )}
compiler/GHC/Tc/Gen/Expr.hs view
@@ -40,6 +40,7 @@ import GHC.Core.Multiplicity import GHC.Core.UsageEnv import GHC.Tc.Errors.Types+import GHC.Tc.Utils.Concrete ( hasFixedRuntimeRep, mkWpFun ) import GHC.Tc.Utils.Instantiate import GHC.Tc.Gen.App import GHC.Tc.Gen.Head@@ -344,7 +345,16 @@ ; (coi, arg_tys) <- matchExpectedTyConApp sum_tc res_ty ; -- Drop levity vars, we don't care about them here let arg_tys' = drop arity arg_tys- ; expr' <- tcCheckPolyExpr expr (arg_tys' `getNth` (alt - 1))+ arg_ty = arg_tys' `getNth` (alt - 1)+ ; expr' <- tcCheckPolyExpr expr arg_ty+ -- Check the whole res_ty, not just the arg_ty, to avoid #20277.+ -- Example:+ -- a :: TYPE rep (representation-polymorphic)+ -- (# 17# | #) :: (# Int# | a #)+ -- This should cause an error, even though (17# :: Int#)+ -- is not representation-polymorphic: we don't know how+ -- wide the concrete representation of the sum type will be.+ ; _concrete_ev <- hasFixedRuntimeRep FRRUnboxedSum res_ty ; return $ mkHsWrapCo coi (ExplicitSum arg_tys' alt arity expr' ) } @@ -738,7 +748,7 @@ con1_tv_set = mkVarSet con1_tvs bad_fld (fld, ty) = fld `elem` upd_fld_occs && not (tyCoVarsOfType ty `subVarSet` con1_tv_set)- ; checkTc (null bad_upd_flds) (badFieldTypes bad_upd_flds)+ ; checkTc (null bad_upd_flds) (TcRnFieldUpdateInvalidType bad_upd_flds) -- STEP 4 Note [Type of a record update] -- Figure out types for the scrutinee and result@@ -938,12 +948,17 @@ tcTupArgs args tys = do massert (equalLength args tys) checkTupSize (length args)- mapM go (args `zip` tys)+ zipWith3M go [1,2..] args tys where- go (Missing {}, arg_ty) = do { mult <- newFlexiTyVarTy multiplicityTy- ; return (Missing (Scaled mult arg_ty)) }- go (Present x expr, arg_ty) = do { expr' <- tcCheckPolyExpr expr arg_ty- ; return (Present x expr') }+ go :: Int -> HsTupArg GhcRn -> TcType -> TcM (HsTupArg GhcTc)+ go i (Missing {}) arg_ty+ = do { mult <- newFlexiTyVarTy multiplicityTy+ ; _concrete_ev <- hasFixedRuntimeRep (FRRTupleSection i) arg_ty+ ; return (Missing (Scaled mult arg_ty)) }+ go i (Present x expr) arg_ty+ = do { expr' <- tcCheckPolyExpr expr arg_ty+ ; _concrete_ev <- hasFixedRuntimeRep (FRRTupleArg i) arg_ty+ ; return (Present x expr') } --------------------------- -- See TcType.SyntaxOpType also for commentary@@ -1003,8 +1018,8 @@ -- ^ returns a wrapper :: (type of right shape) "->" (type passed in) tcSynArgE orig sigma_ty syn_ty thing_inside = do { (skol_wrap, (result, ty_wrapper))- <- tcSkolemise GenSigCtxt sigma_ty $ \ rho_ty ->- go rho_ty syn_ty+ <- tcSkolemise GenSigCtxt sigma_ty+ (\ rho_ty -> go rho_ty syn_ty) ; return (result, skol_wrap <.> ty_wrapper) } where go rho_ty SynAny@@ -1046,13 +1061,11 @@ do { result <- thing_inside (arg_results ++ res_results) ([arg_mult] ++ arg_res_mults ++ res_res_mults) ; return (result, arg_tc_ty, res_tc_ty, arg_mult) }} - ; return ( result- , match_wrapper <.>- mkWpFun (arg_wrapper2 <.> arg_wrapper1) res_wrapper- (Scaled op_mult arg_ty) res_ty doc ) }+ ; fun_wrap <- mkWpFun (arg_wrapper2 <.> arg_wrapper1) res_wrapper+ (Scaled op_mult arg_ty) res_ty (WpFunSyntaxOp orig)+ ; return (result, match_wrapper <.> fun_wrap) } where herald = text "This rebindable syntax expects a function with"- doc = text "When checking a rebindable syntax operator arising from" <+> ppr orig go rho_ty (SynType the_ty) = do { wrap <- tcSubTypePat orig GenSigCtxt the_ty rho_ty@@ -1218,7 +1231,7 @@ identifyParent fam_inst_envs possible_parents = case foldr1 intersect possible_parents of -- No parents for all fields: record update is ill-typed- [] -> failWithTc (noPossibleParents rbnds)+ [] -> failWithTc (TcRnNoPossibleParentForFields rbnds) -- Exactly one datatype with all the fields: use that [p] -> return p@@ -1237,7 +1250,7 @@ ; return (RecSelData tc) } -- Nothing else we can try...- _ -> failWithTc badOverloadedUpdate+ _ -> failWithTc (TcRnBadOverloadedRecordUpdate rbnds) -- Make a field unambiguous by choosing the given parent. -- Emits an error if the field cannot have that parent,@@ -1286,13 +1299,7 @@ -- See Note [Deprecating ambiguous fields] in GHC.Tc.Gen.Head reportAmbiguousField :: TyCon -> TcM () reportAmbiguousField parent_type =- setSrcSpan loc $ addDiagnostic $- TcRnUnknownMessage $ mkPlainDiagnostic (WarningWithFlag Opt_WarnAmbiguousFields) noHints $- vcat [ text "The record update" <+> ppr rupd- <+> text "with type" <+> ppr parent_type- <+> text "is ambiguous."- , text "This will not be supported by -XDuplicateRecordFields in future releases of GHC."- ]+ setSrcSpan loc $ addDiagnostic $ TcRnAmbiguousField rupd parent_type where rupd = RecordUpd { rupd_expr = record_expr, rupd_flds = Left rbnds, rupd_ext = noExtField } loc = getLocA (head rbnds)@@ -1380,6 +1387,9 @@ | Just field_ty <- assocMaybe flds_w_tys sel_name = addErrCtxt (fieldCtxt field_lbl) $ do { rhs' <- tcCheckPolyExprNC rhs field_ty+ ; _concrete_ev <-+ hasFixedRuntimeRep (FRRRecordUpdate (unLoc lbl) (unLoc rhs))+ field_ty ; let field_id = mkUserLocal (nameOccName sel_name) (nameUnique sel_name) Many field_ty loc@@ -1401,13 +1411,10 @@ -- But C{} is still valid if no strict fields = if any isBanged field_strs then -- Illegal if any arg is strict- addErrTc (missingStrictFields con_like [])+ addErrTc (TcRnMissingStrictFields con_like []) else do when (notNull field_strs && null field_labels) $ do- let msg = TcRnUnknownMessage $- mkPlainDiagnostic (WarningWithFlag Opt_WarnMissingFields)- noHints- (missingFields con_like [])+ let msg = TcRnMissingFields con_like [] (diagnosticTc True msg) | otherwise = do -- A record@@ -1415,7 +1422,7 @@ fs <- zonk_fields missing_s_fields -- It is an error to omit a strict field, because -- we can't substitute it with (error "Missing field f")- addErrTc (missingStrictFields con_like fs)+ addErrTc (TcRnMissingStrictFields con_like fs) warn <- woptM Opt_WarnMissingFields when (warn && notNull missing_ns_fields) $ do@@ -1423,10 +1430,7 @@ -- It is not an error (though we may want) to omit a -- lazy field, because we can always use -- (error "Missing field f") instead.- let msg = TcRnUnknownMessage $- mkPlainDiagnostic (WarningWithFlag Opt_WarnMissingFields)- noHints- (missingFields con_like fs)+ let msg = TcRnMissingFields con_like fs diagnosticTc True msg where@@ -1468,22 +1472,13 @@ fieldCtxt field_name = text "In the" <+> quotes (ppr field_name) <+> text "field of a record" -badFieldTypes :: [(FieldLabelString,TcType)] -> TcRnMessage-badFieldTypes prs- = TcRnUnknownMessage $ mkPlainError noHints $- hang (text "Record update for insufficiently polymorphic field"- <> plural prs <> colon)- 2 (vcat [ ppr f <+> dcolon <+> ppr ty | (f,ty) <- prs ])- badFieldsUpd :: [LHsFieldBind GhcTc (LAmbiguousFieldOcc GhcTc) (LHsExpr GhcRn)] -- Field names that don't belong to a single datacon -> [ConLike] -- Data cons of the type which the first field name belongs to -> TcRnMessage badFieldsUpd rbinds data_cons- = TcRnUnknownMessage $ mkPlainError noHints $- hang (text "No constructor has all these fields:")- 2 (pprQuotedList conflictingFields)+ = TcRnNoConstructorHasAllFields conflictingFields -- See Note [Finding the conflicting fields] where -- A (preferably small) set of fields such that no constructor contains@@ -1554,60 +1549,12 @@ mixedSelectors :: [Id] -> [Id] -> TcRnMessage mixedSelectors data_sels@(dc_rep_id:_) pat_syn_sels@(ps_rep_id:_)- = TcRnUnknownMessage $ mkPlainError noHints $- text "Cannot use a mixture of pattern synonym and record selectors" $$- text "Record selectors defined by"- <+> quotes (ppr (tyConName rep_dc))- <> colon- <+> pprWithCommas ppr data_sels $$- text "Pattern synonym selectors defined by"- <+> quotes (ppr (patSynName rep_ps))- <> colon- <+> pprWithCommas ppr pat_syn_sels+ = TcRnMixedSelectors (tyConName rep_dc) data_sels (patSynName rep_ps) pat_syn_sels where RecSelPatSyn rep_ps = recordSelectorTyCon ps_rep_id RecSelData rep_dc = recordSelectorTyCon dc_rep_id mixedSelectors _ _ = panic "GHC.Tc.Gen.Expr: mixedSelectors emptylists" --missingStrictFields :: ConLike -> [(FieldLabelString, TcType)] -> TcRnMessage-missingStrictFields con fields- = TcRnUnknownMessage $ mkPlainError noHints $ vcat [header, nest 2 rest]- where- pprField (f,ty) = ppr f <+> dcolon <+> ppr ty- rest | null fields = Outputable.empty -- Happens for non-record constructors- -- with strict fields- | otherwise = vcat (fmap pprField fields)-- header = text "Constructor" <+> quotes (ppr con) <+>- text "does not have the required strict field(s)" <>- if null fields then Outputable.empty else colon--missingFields :: ConLike -> [(FieldLabelString, TcType)] -> SDoc-missingFields con fields- = vcat [header, nest 2 rest]- where- pprField (f,ty) = ppr f <+> text "::" <+> ppr ty- rest | null fields = Outputable.empty- | otherwise = vcat (fmap pprField fields)- header = text "Fields of" <+> quotes (ppr con) <+>- text "not initialised" <>- if null fields then Outputable.empty else colon---- callCtxt fun args = text "In the call" <+> parens (ppr (foldl' mkHsApp fun args))--noPossibleParents :: [LHsRecUpdField GhcRn] -> TcRnMessage-noPossibleParents rbinds- = TcRnUnknownMessage $ mkPlainError noHints $- hang (text "No type has all these fields:")- 2 (pprQuotedList fields)- where- fields = map (hfbLHS . unLoc) rbinds--badOverloadedUpdate :: TcRnMessage-badOverloadedUpdate = TcRnUnknownMessage $ mkPlainError noHints $- text "Record update is ambiguous, and requires a type signature"- {- ************************************************************************ * *@@ -1616,11 +1563,6 @@ ************************************************************************ -} --- | A data type to describe why a variable is not closed.-data NotClosedReason = NotLetBoundReason- | NotTypeClosed VarSet- | NotClosed Name NotClosedReason- -- | Checks if the given name is closed and emits an error if not. -- -- See Note [Not-closed error messages].@@ -1686,25 +1628,7 @@ -- when the final node has a non-closed type. -- explain :: Name -> NotClosedReason -> TcRnMessage- explain name reason = TcRnUnknownMessage $ mkPlainError noHints $- quotes (ppr name) <+> text "is used in a static form but it is not closed"- <+> text "because it"- $$- sep (causes reason)-- causes :: NotClosedReason -> [SDoc]- causes NotLetBoundReason = [text "is not let-bound."]- causes (NotTypeClosed vs) =- [ text "has a non-closed type because it contains the"- , text "type variables:" <+>- pprVarSet vs (hsep . punctuate comma . map (quotes . ppr))- ]- causes (NotClosed n reason) =- let msg = text "uses" <+> quotes (ppr n) <+> text "which"- in case reason of- NotClosed _ _ -> msg : causes reason- _ -> let (xs0, xs1) = splitAt 1 $ causes reason- in fmap (msg <+>) xs0 ++ xs1+ explain = TcRnStaticFormNotClosed -- Note [Not-closed error messages] -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compiler/GHC/Tc/Gen/Head.hs view
@@ -22,6 +22,7 @@ , splitHsApps, rebuildHsApps , addArgWrap, isHsValArg , countLeadingValArgs, isVisibleArg, pprHsExprArgTc+ , countVisAndInvisValArgs, countHsWrapperInvisArgs , tcInferAppHead, tcInferAppHead_maybe , tcInferId, tcCheckId@@ -75,6 +76,7 @@ import GHC.Utils.Misc import GHC.Data.Maybe import GHC.Utils.Outputable as Outputable+import GHC.Utils.Panic import GHC.Utils.Panic.Plain import Control.Monad @@ -322,6 +324,36 @@ isVisibleArg (EValArg {}) = True isVisibleArg (ETypeArg {}) = True isVisibleArg _ = False++-- | Count visible and invisible value arguments in a list+-- of 'HsExprArg' arguments.+countVisAndInvisValArgs :: [HsExprArg id] -> Arity+countVisAndInvisValArgs [] = 0+countVisAndInvisValArgs (EValArg {} : args) = 1 + countVisAndInvisValArgs args+countVisAndInvisValArgs (EWrap wrap : args) =+ case wrap of { EHsWrap hsWrap -> countHsWrapperInvisArgs hsWrap + countVisAndInvisValArgs args+ ; EPar {} -> countVisAndInvisValArgs args+ ; EExpand {} -> countVisAndInvisValArgs args }+countVisAndInvisValArgs (EPrag {} : args) = countVisAndInvisValArgs args+countVisAndInvisValArgs (ETypeArg {}: args) = countVisAndInvisValArgs args++-- | Counts the number of invisible term-level arguments applied by an 'HsWrapper'.+-- Precondition: this wrapper contains no abstractions.+countHsWrapperInvisArgs :: HsWrapper -> Arity+countHsWrapperInvisArgs = go+ where+ go WpHole = 0+ go (WpCompose wrap1 wrap2) = go wrap1 + go wrap2+ go fun@(WpFun {}) = nope fun+ go (WpCast {}) = 0+ go evLam@(WpEvLam {}) = nope evLam+ go (WpEvApp _) = 1+ go tyLam@(WpTyLam {}) = nope tyLam+ go (WpTyApp _) = 0+ go (WpLet _) = 0+ go (WpMultCoercion {}) = 0++ nope x = pprPanic "countHsWrapperInvisApps" (ppr x) instance OutputableBndrId (XPass p) => Outputable (HsExprArg p) where ppr (EValArg { eva_arg = arg }) = text "EValArg" <+> ppr arg
compiler/GHC/Tc/Gen/HsType.hs view
@@ -2396,7 +2396,7 @@ candidates = candidates' { dv_kvs = dv_kvs candidates' `extendDVarSetList` non_tc_candidates } inf_candidates = candidates `delCandidates` spec_req_tkvs - ; inferred <- quantifyTyVars inf_candidates+ ; inferred <- quantifyTyVars allVarsOfKindDefault inf_candidates -- NB: 'inferred' comes back sorted in dependency order ; scoped_kvs <- mapM zonkTyCoVarKind scoped_kvs@@ -3505,7 +3505,7 @@ -- thus, every free variable is really a kv, never a tv. ; dvs <- candidateQTyVarsOfKind kind_or_type ; dvs <- filterConstrainedCandidates wanted dvs- ; quantifyTyVars dvs }+ ; quantifyTyVars allVarsOfKindDefault dvs } filterConstrainedCandidates :: WantedConstraints -- Don't quantify over variables free in these@@ -3533,7 +3533,7 @@ kindGeneralizeAll kind_or_type = do { traceTc "kindGeneralizeAll" (ppr kind_or_type) ; dvs <- candidateQTyVarsOfKind kind_or_type- ; quantifyTyVars dvs }+ ; quantifyTyVars allVarsOfKindDefault dvs } -- | Specialized version of 'kindGeneralizeSome', but where no variables -- can be generalized, but perhaps some may need to be promoted.@@ -4094,10 +4094,11 @@ ordinary tuples we don't have the same limit as for constraint tuples (which need selectors and an associated class). -* Because it is ill-kinded, it trips an assert in writeMetaTyVar,- so now I disable the assertion if we are writing a type of- kind Constraint. (That seldom/never normally happens so we aren't- losing much.)+* 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
@@ -49,6 +49,7 @@ import GHC.Tc.Utils.TcMType import GHC.Tc.Utils.TcType import GHC.Tc.Gen.Bind+import GHC.Tc.Utils.Concrete ( hasFixedRuntimeRep ) import GHC.Tc.Utils.Unify import GHC.Tc.Types.Origin import GHC.Tc.Types.Evidence@@ -226,6 +227,10 @@ = do { tcEmitBindingUsage bottomUE ; pat_tys <- mapM scaledExpTypeToType pat_tys ; rhs_ty <- expTypeToType rhs_ty+ ; _concrete_evs <- zipWithM+ (\ i (Scaled _ pat_ty) ->+ hasFixedRuntimeRep (FRRMatch (mc_what ctxt) i) pat_ty)+ [1..] pat_tys ; return (MG { mg_alts = L l [] , mg_ext = MatchGroupTc pat_tys rhs_ty , mg_origin = origin }) }@@ -236,6 +241,10 @@ ; tcEmitBindingUsage $ supUEs usages ; pat_tys <- mapM readScaledExpType pat_tys ; rhs_ty <- readExpType rhs_ty+ ; _concrete_evs <- zipWithM+ (\ i (Scaled _ pat_ty) ->+ hasFixedRuntimeRep (FRRMatch (mc_what ctxt) i) pat_ty)+ [1..] pat_tys ; return (MG { mg_alts = L l matches' , mg_ext = MatchGroupTc pat_tys rhs_ty , mg_origin = origin }) }@@ -431,6 +440,7 @@ -- two multiplicity to still be the same. (rhs', rhs_ty) <- tcScalingUsage Many $ tcInferRhoNC rhs -- Stmt has a context already+ ; _concrete_ev <- hasFixedRuntimeRep FRRBindStmtGuard rhs_ty ; (pat', thing) <- tcCheckPat_O (StmtCtxt ctxt) (lexprCtOrigin rhs) pat (unrestricted rhs_ty) $ thing_inside res_ty@@ -583,15 +593,17 @@ tcMcStmt ctxt (BindStmt xbsrn pat rhs) res_ty thing_inside -- (>>=) :: rhs_ty -> (pat_ty -> new_res_ty) -> res_ty- = do { ((rhs', pat_mult, pat', thing, new_res_ty), bind_op')+ = do { ((rhs_ty, rhs', pat_mult, pat', thing, new_res_ty), bind_op') <- tcSyntaxOp MCompOrigin (xbsrn_bindOp xbsrn) [SynRho, SynFun SynAny SynRho] res_ty $ \ [rhs_ty, pat_ty, new_res_ty] [rhs_mult, fun_mult, pat_mult] -> do { rhs' <- tcScalingUsage rhs_mult $ tcCheckMonoExprNC rhs rhs_ty ; (pat', thing) <- tcScalingUsage fun_mult $ tcCheckPat (StmtCtxt ctxt) pat (Scaled pat_mult pat_ty) $ thing_inside (mkCheckExpType new_res_ty)- ; return (rhs', pat_mult, pat', thing, new_res_ty) }+ ; return (rhs_ty, rhs', pat_mult, pat', thing, new_res_ty) } + ; _concrete_ev <- hasFixedRuntimeRep (FRRBindStmt MonadComprehension) rhs_ty+ -- If (but only if) the pattern can fail, typecheck the 'fail' operator ; fail_op' <- fmap join . forM (xbsrn_failOp xbsrn) $ \fail -> tcMonadFailOp (MCompPatOrigin pat) pat' fail new_res_ty@@ -613,17 +625,23 @@ -- guard_op :: test_ty -> rhs_ty -- then_op :: rhs_ty -> new_res_ty -> res_ty -- Where test_ty is, for example, Bool- ; ((thing, rhs', rhs_ty, guard_op'), then_op')+ ; ((thing, rhs', rhs_ty, new_res_ty, test_ty, guard_op'), then_op') <- tcSyntaxOp MCompOrigin then_op [SynRho, SynRho] res_ty $ \ [rhs_ty, new_res_ty] [rhs_mult, fun_mult] ->- do { (rhs', guard_op')+ do { ((rhs', test_ty), guard_op') <- tcScalingUsage rhs_mult $ tcSyntaxOp MCompOrigin guard_op [SynAny] (mkCheckExpType rhs_ty) $- \ [test_ty] [test_mult] ->- tcScalingUsage test_mult $ tcCheckMonoExpr rhs test_ty+ \ [test_ty] [test_mult] -> do+ rhs' <- tcScalingUsage test_mult $ tcCheckMonoExpr rhs test_ty+ return $ (rhs', test_ty) ; thing <- tcScalingUsage fun_mult $ thing_inside (mkCheckExpType new_res_ty)- ; return (thing, rhs', rhs_ty, guard_op') }+ ; return (thing, rhs', rhs_ty, new_res_ty, test_ty, guard_op') }++ ; _evTerm1 <- hasFixedRuntimeRep FRRBodyStmtGuard test_ty+ ; _evTerm2 <- hasFixedRuntimeRep (FRRBodyStmt MonadComprehension 1) rhs_ty+ ; _evTerm3 <- hasFixedRuntimeRep (FRRBodyStmt MonadComprehension 2) new_res_ty+ ; return (BodyStmt rhs_ty rhs' then_op' guard_op', thing) } -- Grouping statements@@ -850,14 +868,16 @@ -- This level of generality is needed for using do-notation -- in full generality; see #1537 - ((rhs', pat_mult, pat', new_res_ty, thing), bind_op')+ ((rhs_ty, rhs', pat_mult, pat', new_res_ty, thing), bind_op') <- tcSyntaxOp DoOrigin (xbsrn_bindOp xbsrn) [SynRho, SynFun SynAny SynRho] res_ty $ \ [rhs_ty, pat_ty, new_res_ty] [rhs_mult,fun_mult,pat_mult] -> do { rhs' <-tcScalingUsage rhs_mult $ tcCheckMonoExprNC rhs rhs_ty ; (pat', thing) <- tcScalingUsage fun_mult $ tcCheckPat (StmtCtxt ctxt) pat (Scaled pat_mult pat_ty) $ thing_inside (mkCheckExpType new_res_ty)- ; return (rhs', pat_mult, pat', new_res_ty, thing) }+ ; return (rhs_ty, rhs', pat_mult, pat', new_res_ty, thing) } + ; _concrete_ev <- hasFixedRuntimeRep (FRRBindStmt DoNotation) rhs_ty+ -- If (but only if) the pattern can fail, typecheck the 'fail' operator ; fail_op' <- fmap join . forM (xbsrn_failOp xbsrn) $ \fail -> tcMonadFailOp (DoPatOrigin pat) pat' fail new_res_ty@@ -884,12 +904,14 @@ tcDoStmt _ (BodyStmt _ rhs then_op _) res_ty thing_inside = do { -- Deal with rebindable syntax; -- (>>) :: rhs_ty -> new_res_ty -> res_ty- ; ((rhs', rhs_ty, thing), then_op')+ ; ((rhs', rhs_ty, new_res_ty, thing), then_op') <- tcSyntaxOp DoOrigin then_op [SynRho, SynRho] res_ty $ \ [rhs_ty, new_res_ty] [rhs_mult,fun_mult] -> do { rhs' <- tcScalingUsage rhs_mult $ tcCheckMonoExprNC rhs rhs_ty ; thing <- tcScalingUsage fun_mult $ thing_inside (mkCheckExpType new_res_ty)- ; return (rhs', rhs_ty, thing) }+ ; return (rhs', rhs_ty, new_res_ty, thing) }+ ; _evTerm1 <- hasFixedRuntimeRep (FRRBodyStmt DoNotation 1) rhs_ty+ ; _evTerm2 <- hasFixedRuntimeRep (FRRBodyStmt DoNotation 2) new_res_ty ; return (BodyStmt rhs_ty rhs' then_op' noSyntaxExpr, thing) } tcDoStmt ctxt (RecStmt { recS_stmts = L l stmts, recS_later_ids = later_names
compiler/GHC/Tc/Gen/Pat.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeFamilies #-}@@ -35,6 +36,7 @@ import GHC.Tc.Errors.Types import GHC.Tc.Utils.Zonk import GHC.Tc.Gen.Sig( TcPragEnv, lookupPragEnv, addInlinePrags )+import GHC.Tc.Utils.Concrete ( mkWpFun ) import GHC.Tc.Utils.Monad import GHC.Tc.Utils.Instantiate import GHC.Types.Error@@ -444,12 +446,12 @@ ; let Scaled w h_pat_ty = pat_ty ; pat_ty <- readExpType h_pat_ty- ; let expr_wrap2' = mkWpFun expr_wrap2 idHsWrapper- (Scaled w pat_ty) inf_res_sigma doc- -- expr_wrap2' :: (inf_arg_ty -> inf_res_sigma) "->"- -- (pat_ty -> inf_res_sigma)+ ; expr_wrap2' <- mkWpFun expr_wrap2 idHsWrapper+ (Scaled w pat_ty) inf_res_sigma (WpFunViewPat $ unLoc expr)+ -- expr_wrap2' :: (inf_arg_ty -> inf_res_sigma) "->"+ -- (pat_ty -> inf_res_sigma)+ ; let expr_wrap = expr_wrap2' <.> expr_wrap1 <.> mult_wrap- doc = text "When checking the view pattern function:" <+> (ppr expr) ; return $ (ViewPat pat_ty (mkLHsWrap expr_wrap expr') pat', res) } @@ -655,6 +657,7 @@ ; return (lit2', wrap, bndr_id) } ; pat_ty <- readExpType pat_exp_ty+ -- The Report says that n+k patterns must be in Integral -- but it's silly to insist on this in the RebindableSyntax case ; unlessM (xoptM LangExt.RebindableSyntax) $@@ -886,8 +889,10 @@ -- Add the stupid theta ; setSrcSpanA con_span $ addDataConStupidTheta data_con ctxt_res_tys + -- Check that this isn't a GADT pattern match+ -- in situations in which that isn't allowed. ; let all_arg_tys = eqSpecPreds eq_spec ++ theta ++ (map scaledThing arg_tys)- ; checkExistentials ex_tvs all_arg_tys penv+ ; checkGADT (RealDataCon data_con) ex_tvs all_arg_tys penv ; tenv1 <- instTyVarsWith PatOrigin univ_tvs ctxt_res_tys -- NB: Do not use zipTvSubst! See #14154@@ -979,8 +984,11 @@ ; (subst, univ_tvs') <- newMetaTyVars univ_tvs + -- Check that we aren't matching on a GADT-like pattern synonym+ -- in situations in which that isn't allowed. ; let all_arg_tys = ty : prov_theta ++ (map scaledThing arg_tys)- ; checkExistentials ex_tvs all_arg_tys penv+ ; checkGADT (PatSynCon pat_syn) ex_tvs all_arg_tys penv+ ; (tenv, ex_tvs') <- tcInstSuperSkolTyVarsX subst ex_tvs -- This freshens: Note [Freshen existentials] @@ -1206,9 +1214,11 @@ { checkTc (con_arity == no_of_args) -- Check correct arity (arityErr (text "constructor") con_like con_arity no_of_args) - ; let con_binders = conLikeUserTyVarBinders con_like- ; checkTc (type_args `leLength` con_binders)- (conTyArgArityErr con_like (length con_binders) (length type_args))+ -- forgetting to filter out inferred binders led to #20443+ ; let con_spec_binders = filter ((== SpecifiedSpec) . binderArgFlag) $+ conLikeUserTyVarBinders con_like+ ; checkTc (type_args `leLength` con_spec_binders)+ (conTyArgArityErr con_like (length con_spec_binders) (length type_args)) ; let pats_w_tys = zipEqual "tcConArgs" arg_pats arg_tys ; (type_args', (arg_pats', res))@@ -1218,7 +1228,7 @@ -- This unification is straight from Figure 7 of -- "Type Variables in Patterns", Haskell'18 ; _ <- zipWithM (unifyType Nothing) type_args' (substTyVars tenv $- binderVars con_binders)+ binderVars con_spec_binders) -- OK to drop coercions here. These unifications are all about -- guiding inference based on a user-written type annotation -- See Note [Typechecking type applications in patterns]@@ -1344,12 +1354,16 @@ The Right Thing is not to confuse these constraints together. But for now the Easy Thing is to ensure that we do not have existential or-GADT constraints in a 'proc', and to short-cut the constraint-simplification for such vanilla patterns so that it binds no-constraints. Hence the 'fast path' in tcConPat; but it's also a good-plan for ordinary vanilla patterns to bypass the constraint-simplification step.+GADT constraints in a 'proc', which we do by disallowing any+non-vanilla pattern match (i.e. one that introduces existential+variables or provided constraints), in tcDataConPat and tcPatSynPat. +We also short-cut the constraint simplification for such vanilla patterns,+so that we bind no constraints. Hence the 'fast path' in tcDataConPat;+which applies more generally (not just within 'proc'), as it's a good+plan in general to bypass the constraint simplification step entirely+when it's not needed.+ ************************************************************************ * * Note [Pattern coercions]@@ -1442,28 +1456,30 @@ msg = hang (text "In the pattern:") 2 (ppr pat) ------------------------------------------------checkExistentials :: [TyVar] -- existentials- -> [Type] -- argument types- -> PatEnv -> TcM ()- -- See Note [Existential check]]- -- See Note [Arrows and patterns]-checkExistentials ex_tvs tys _- | all (not . (`elemVarSet` tyCoVarsOfTypes tys)) ex_tvs = return ()-checkExistentials _ _ (PE { pe_ctxt = LetPat {}}) = return ()-checkExistentials _ _ (PE { pe_ctxt = LamPat ProcExpr }) = failWithTc existentialProcPat-checkExistentials _ _ (PE { pe_lazy = True }) = failWithTc existentialLazyPat-checkExistentials _ _ _ = return () -existentialLazyPat :: TcRnMessage-existentialLazyPat- = TcRnUnknownMessage $ mkPlainError noHints $- hang (text "An existential or GADT data constructor cannot be used")- 2 (text "inside a lazy (~) pattern")--existentialProcPat :: TcRnMessage-existentialProcPat- = TcRnUnknownMessage $ mkPlainError noHints $- text "Proc patterns cannot use existential or GADT data constructors"+-- | Check that a pattern isn't a GADT, or doesn't have existential variables,+-- in a situation in which that is not permitted (inside a lazy pattern, or+-- in arrow notation).+checkGADT :: ConLike+ -> [TyVar] -- ^ existentials+ -> [Type] -- ^ argument types+ -> PatEnv+ -> TcM ()+checkGADT conlike ex_tvs arg_tys = \case+ PE { pe_ctxt = LetPat {} }+ -> return ()+ PE { pe_ctxt = LamPat (ArrowMatchCtxt {}) }+ | not $ isVanillaConLike conlike+ -- See Note [Arrows and patterns]+ -> failWithTc TcRnArrowProcGADTPattern+ PE { pe_lazy = True }+ | has_existentials+ -- See Note [Existential check]+ -> failWithTc TcRnLazyGADTPattern+ _ -> return ()+ where+ has_existentials :: Bool+ has_existentials = any (`elemVarSet` tyCoVarsOfTypes arg_tys) ex_tvs badFieldCon :: ConLike -> FieldLabelString -> TcRnMessage badFieldCon con field
compiler/GHC/Tc/Gen/Rule.hs view
@@ -30,7 +30,7 @@ import GHC.Types.Id import GHC.Types.Var( EvVar ) import GHC.Types.Var.Set-import GHC.Types.Basic ( RuleName )+import GHC.Types.Basic ( RuleName, allVarsOfKindDefault ) import GHC.Types.SrcLoc import GHC.Utils.Outputable import GHC.Utils.Panic@@ -151,7 +151,7 @@ -- See Note [Re-quantify type variables in rules] ; forall_tkvs <- candidateQTyVarsOfTypes (rule_ty : map idType tpl_ids)- ; qtkvs <- quantifyTyVars forall_tkvs+ ; qtkvs <- quantifyTyVars allVarsOfKindDefault forall_tkvs ; traceTc "tcRule" (vcat [ pprFullRuleName rname , ppr forall_tkvs , ppr qtkvs@@ -477,12 +477,17 @@ new_skol_tvs = skol_tvs `extendVarSetList` ic_skols imp rule_quant_ct :: TcTyCoVarSet -> Ct -> Bool- rule_quant_ct skol_tvs ct- | EqPred _ t1 t2 <- classifyPredType (ctPred ct)- , not (ok_eq t1 t2)- = False -- Note [RULE quantification over equalities]- | otherwise- = tyCoVarsOfCt ct `disjointVarSet` skol_tvs+ rule_quant_ct skol_tvs ct = case classifyPredType (ctPred ct) of+ EqPred _ t1 t2+ | not (ok_eq t1 t2)+ -> False -- Note [RULE quantification over equalities]+ SpecialPred {}+ -- RULES must never quantify over special predicates, as that+ -- would leak internal GHC implementation details to the user.+ --+ -- Tests (for Concrete# predicates): RepPolyRule{1,2,3}.+ -> False+ _ -> tyCoVarsOfCt ct `disjointVarSet` skol_tvs ok_eq t1 t2 | t1 `tcEqType` t2 = False
compiler/GHC/Tc/Gen/Sig.hs view
@@ -32,15 +32,15 @@ import GHC.Hs -import GHC.Tc.Errors.Types ( TcRnMessage(..), LevityCheckProvenance(..) )+import GHC.Tc.Errors.Types ( FixedRuntimeRepProvenance(..), TcRnMessage(..) ) import GHC.Tc.Gen.HsType import GHC.Tc.Types import GHC.Tc.Solver( pushLevelAndSolveEqualitiesX, reportUnsolvedEqualities ) import GHC.Tc.Utils.Monad+import GHC.Tc.Utils.TcMType ( checkTypeHasFixedRuntimeRep ) import GHC.Tc.Utils.Zonk import GHC.Tc.Types.Origin import GHC.Tc.Utils.TcType-import GHC.Tc.Utils.TcMType import GHC.Tc.Validity ( checkValidType ) import GHC.Tc.Utils.Unify( tcSkolemise, unifyType ) import GHC.Tc.Utils.Instantiate( topInstantiate, tcInstTypeBndrs )@@ -452,10 +452,15 @@ ; checkValidType ctxt $ build_patsyn_type implicit_bndrs univ_bndrs req ex_bndrs prov body_ty - -- arguments become the types of binders. We thus cannot allow- -- representation polymorphism here- ; let (arg_tys, _) = tcSplitFunTys body_ty- ; mapM_ (checkForLevPoly LevityCheckPatSynSig . scaledThing) arg_tys+ -- Neither argument types nor the return type may be representation polymorphic.+ -- This is because, when creating a matcher:+ -- - the argument types become the the binder types (see test RepPolyPatySynArg),+ -- - the return type becomes the scrutinee type (see test RepPolyPatSynRes).+ ; let (arg_tys, res_ty) = tcSplitFunTys body_ty+ ; mapM_+ (\(Scaled _ arg_ty) -> checkTypeHasFixedRuntimeRep FixedRuntimeRepPatSynSigArg arg_ty)+ arg_tys+ ; checkTypeHasFixedRuntimeRep FixedRuntimeRepPatSynSigRes res_ty ; traceTc "tcTySig }" $ vcat [ text "kvs" <+> ppr_tvs (binderVars kv_bndrs)
compiler/GHC/Tc/Instance/Class.hs view
@@ -1,18 +1,18 @@ - {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} module GHC.Tc.Instance.Class ( matchGlobalInst, ClsInstResult(..), InstanceWhat(..), safeOverlap, instanceReturnsDictCon,- AssocInstInfo(..), isNotAssociated+ AssocInstInfo(..), isNotAssociated, ) where import GHC.Prelude import GHC.Driver.Session +import GHC.Core.TyCo.Rep import GHC.Tc.Utils.Env import GHC.Tc.Utils.Monad@@ -25,7 +25,7 @@ import GHC.Rename.Env( addUsedGRE ) import GHC.Builtin.Types-import GHC.Builtin.Types.Prim( eqPrimTyCon, eqReprPrimTyCon )+import GHC.Builtin.Types.Prim import GHC.Builtin.Names import GHC.Types.Name.Reader( lookupGRE_FieldLabel, greMangledName )@@ -37,7 +37,7 @@ import GHC.Core.Predicate import GHC.Core.InstEnv import GHC.Core.Type-import GHC.Core.Make ( mkCharExpr, mkStringExprFS, mkNaturalExpr )+import GHC.Core.Make ( mkCharExpr, mkNaturalExpr, mkStringExprFS ) import GHC.Core.DataCon import GHC.Core.TyCon import GHC.Core.Class@@ -608,7 +608,6 @@ where args' = [k, k, t1, t2] matchCoercible args = pprPanic "matchLiftedCoercible" (ppr args)- {- ******************************************************************** * *
compiler/GHC/Tc/Instance/FunDeps.hs view
@@ -40,7 +40,7 @@ import GHC.Utils.Outputable import GHC.Utils.FV-import GHC.Utils.Error( Validity(..), allValid )+import GHC.Utils.Error( Validity'(..), Validity, allValid ) import GHC.Utils.Misc import GHC.Utils.Panic
compiler/GHC/Tc/Module.hs view
@@ -153,9 +153,9 @@ import GHC.Types.Basic hiding( SuccessFlag(..) ) import GHC.Types.Annotations import GHC.Types.SrcLoc-import GHC.Types.SourceText import GHC.Types.SourceFile import GHC.Types.TyThing.Ppr ( pprTyThingInContext )+import GHC.Types.PkgQual import qualified GHC.LanguageExtensions as LangExt import GHC.Unit.External@@ -204,7 +204,9 @@ (text "Renamer/typechecker"<+>brackets (ppr this_mod)) (const ()) $ initTc hsc_env hsc_src save_rn_syntax this_mod real_loc $- withTcPlugins hsc_env $ withHoleFitPlugins hsc_env $+ withTcPlugins hsc_env $+ withDefaultingPlugins hsc_env $+ withHoleFitPlugins hsc_env $ tcRnModuleTcRnM hsc_env mod_sum parsedModule pair @@ -221,7 +223,7 @@ pair :: (Module, SrcSpan) pair@(this_mod,_) | Just (L mod_loc mod) <- hsmodName this_module- = (mkHomeModule home_unit mod, mod_loc)+ = (mkHomeModule home_unit mod, locA mod_loc) | otherwise -- 'module M where' is omitted = (mkHomeModule home_unit mAIN_NAME, srcLocSpan (srcSpanStart loc))@@ -268,7 +270,8 @@ ; -- TODO This is a little skeevy; maybe handle a bit more directly let { simplifyImport (L _ idecl) =- ( fmap sl_fs (ideclPkgQual idecl) , ideclName idecl)+ ( renameRawPkgQual (hsc_unit_env hsc_env) (ideclPkgQual idecl)+ , reLoc $ ideclName idecl) } ; raw_sig_imports <- liftIO $ findExtraSigImports hsc_env hsc_src@@ -277,10 +280,9 @@ $ implicitRequirements hsc_env (map simplifyImport (prel_imports ++ import_decls))- ; let { mkImport (Nothing, L _ mod_name) = noLocA+ ; let { mkImport mod_name = noLocA $ (simpleImportDecl mod_name)- { ideclHiding = Just (False, noLocA [])}- ; mkImport _ = panic "mkImport" }+ { ideclHiding = Just (False, noLocA [])}} ; let { withReason t imps = map (,text t) imps } ; let { all_imports = withReason "is implicitly imported" prel_imports ++ withReason "is directly imported" import_decls@@ -1306,7 +1308,7 @@ Nothing -> Just roles_msg -} - eqAlgRhs _ AbstractTyCon _rhs2+ eqAlgRhs _ (AbstractTyCon {}) _rhs2 = checkSuccess -- rhs2 is guaranteed to be injective, since it's an AlgTyCon eqAlgRhs _ tc1@DataTyCon{} tc2@DataTyCon{} = checkListBy eqCon (data_cons tc1) (data_cons tc2) (text "constructors")@@ -2033,12 +2035,13 @@ -- Initialise the tcg_inst_env with instances from all home modules. -- This mimics the more selective call to hptInstances in tcRnImports runTcInteractive hsc_env thing_inside- = initTcInteractive hsc_env $ withTcPlugins hsc_env $ withHoleFitPlugins hsc_env $+ = initTcInteractive hsc_env $ withTcPlugins hsc_env $+ withDefaultingPlugins hsc_env $ withHoleFitPlugins hsc_env $ do { traceTc "setInteractiveContext" $ vcat [ text "ic_tythings:" <+> vcat (map ppr (ic_tythings icxt)) , text "ic_insts:" <+> vcat (map (pprBndr LetBind . instanceDFunId) ic_insts)- , text "ic_rn_gbl_env (LocalDef)" <+>- vcat (map ppr [ local_gres | gres <- nonDetOccEnvElts (ic_rn_gbl_env icxt)+ , text "icReaderEnv (LocalDef)" <+>+ vcat (map ppr [ local_gres | gres <- nonDetOccEnvElts (icReaderEnv icxt) , let local_gres = filter isLocalGRE gres , not (null local_gres) ]) ] @@ -2049,10 +2052,9 @@ ; !orphs <- fmap (force . concat) . forM (ic_imports icxt) $ \i -> case i of -- force above: see #15111- IIModule n -> getOrphans n Nothing- IIDecl i ->- let mb_pkg = sl_fs <$> ideclPkgQual i in- getOrphans (unLoc (ideclName i)) mb_pkg+ IIModule n -> getOrphans n NoPkgQual+ IIDecl i -> getOrphans (unLoc (ideclName i))+ (renameRawPkgQual (hsc_unit_env hsc_env) (ideclPkgQual i)) ; let imports = emptyImportAvails { imp_orphs = orphs@@ -2060,7 +2062,7 @@ ; (gbl_env, lcl_env) <- getEnvs ; let gbl_env' = gbl_env {- tcg_rdr_env = ic_rn_gbl_env icxt+ tcg_rdr_env = icReaderEnv icxt , tcg_type_env = type_env , tcg_inst_env = extendInstEnvList (extendInstEnvList (tcg_inst_env gbl_env) ic_insts)@@ -2907,7 +2909,7 @@ home_unit = hsc_home_unit hsc_env unqual_mods = [ nameModule name- | gre <- globalRdrEnvElts (ic_rn_gbl_env ictxt)+ | gre <- globalRdrEnvElts (icReaderEnv ictxt) , let name = greMangledName gre , nameIsFromExternalPackage home_unit name , isTcOcc (nameOccName name) -- Types and classes only@@ -3086,12 +3088,12 @@ withTcPlugins :: HscEnv -> TcM a -> TcM a withTcPlugins hsc_env m =- case getTcPlugins hsc_env of+ case catMaybes $ mapPlugins hsc_env tcPlugin of [] -> m -- Common fast case plugins -> do ev_binds_var <- newTcEvBinds (solvers, rewriters, stops) <-- unzip3 `fmap` mapM (startPlugin ev_binds_var) plugins+ unzip3 `fmap` mapM (start_plugin ev_binds_var) plugins let rewritersUniqFM :: UniqFM TyCon [TcPluginRewriter] !rewritersUniqFM = sequenceUFMList rewriters@@ -3105,19 +3107,33 @@ Left _ -> failM Right res -> return res where- startPlugin ev_binds_var (TcPlugin start solve rewrite stop) =+ start_plugin ev_binds_var (TcPlugin start solve rewrite stop) = do s <- runTcPluginM start return (solve s ev_binds_var, rewrite s, stop s) -getTcPlugins :: HscEnv -> [GHC.Tc.Utils.Monad.TcPlugin]-getTcPlugins hsc_env = catMaybes $ mapPlugins hsc_env (\p args -> tcPlugin p args)-+withDefaultingPlugins :: HscEnv -> TcM a -> TcM a+withDefaultingPlugins hsc_env m =+ do case catMaybes $ mapPlugins hsc_env defaultingPlugin of+ [] -> m -- Common fast case+ plugins -> do (plugins,stops) <- mapAndUnzipM start_plugin plugins+ -- This ensures that dePluginStop is called even if a type+ -- error occurs during compilation+ eitherRes <- tryM $ do+ updGblEnv (\e -> e { tcg_defaulting_plugins = plugins }) m+ mapM_ runTcPluginM stops+ case eitherRes of+ Left _ -> failM+ Right res -> return res+ where+ start_plugin (DefaultingPlugin start fill stop) =+ do s <- runTcPluginM start+ return (fill s, stop s) withHoleFitPlugins :: HscEnv -> TcM a -> TcM a withHoleFitPlugins hsc_env m =- case getHfPlugins hsc_env of+ case catMaybes $ mapPlugins hsc_env holeFitPlugin of [] -> m -- Common fast case- plugins -> do (plugins,stops) <- unzip `fmap` mapM startPlugin plugins+ plugins -> do (plugins,stops) <- mapAndUnzipM start_plugin plugins -- This ensures that hfPluginStop is called even if a type -- error occurs during compilation. eitherRes <- tryM $@@ -3127,13 +3143,9 @@ Left _ -> failM Right res -> return res where- startPlugin (HoleFitPluginR init plugin stop) =+ start_plugin (HoleFitPluginR init plugin stop) = do ref <- init return (plugin ref, stop ref)--getHfPlugins :: HscEnv -> [HoleFitPluginR]-getHfPlugins hsc_env =- catMaybes $ mapPlugins hsc_env (\p args -> holeFitPlugin p args) runRenamerPlugin :: TcGblEnv
compiler/GHC/Tc/Plugin.hs view
@@ -86,8 +86,8 @@ import GHC.Core.Type ( Kind, Type, PredType ) import GHC.Types.Id ( Id ) import GHC.Core.InstEnv ( InstEnvs )-import GHC.Data.FastString ( FastString ) import GHC.Types.Unique ( Unique )+import GHC.Types.PkgQual ( PkgQual ) -- | Perform some IO, typically to interact with an external tool.@@ -99,7 +99,7 @@ tcPluginTrace a b = unsafeTcPluginTcM (traceTc a b) -findImportedModule :: ModuleName -> Maybe FastString -> TcPluginM Finder.FindResult+findImportedModule :: ModuleName -> PkgQual -> TcPluginM Finder.FindResult findImportedModule mod_name mb_pkg = do hsc_env <- getTopEnv let fc = hsc_FC hsc_env
compiler/GHC/Tc/Solver.hs view
@@ -23,7 +23,11 @@ -- For Rules we need these solveWanteds, solveWantedsAndDrop,- approximateWC, runTcSDeriveds+ approximateWC, runTcSDeriveds,++ -- We need this for valid hole-fits+ runTcSDerivedsEarlyAbort+ ) where import GHC.Prelude@@ -54,13 +58,14 @@ import GHC.Tc.Types.Origin import GHC.Tc.Utils.TcType import GHC.Core.Type-import GHC.Builtin.Types ( liftedRepTy, manyDataConTy )+import GHC.Builtin.Types ( liftedRepTy, manyDataConTy, liftedDataConTy ) import GHC.Core.Unify ( tcMatchTyKi ) import GHC.Utils.Misc import GHC.Utils.Panic import GHC.Types.Var import GHC.Types.Var.Set-import GHC.Types.Basic ( IntWithInf, intGtLimit )+import GHC.Types.Basic ( IntWithInf, intGtLimit+ , DefaultKindVars(..), allVarsOfKindDefault ) import GHC.Types.Error import qualified GHC.LanguageExtensions as LangExt @@ -222,9 +227,11 @@ -- Emit the bad constraints, wrapped in an implication -- See Note [Wrapping failing kind equalities] ; tclvl <- TcM.getTcLevel- ; implic <- buildTvImplication UnkSkol [] tclvl wanted- -- UnkSkol: doesn't matter, because- -- we bind no skolem variables here+ ; implic <- buildTvImplication UnkSkol [] (pushTcLevel tclvl) wanted+ -- ^^^^^^ | ^^^^^^^^^^^^^^^^^+ -- it's OK to use UnkSkol | we must increase the TcLevel,+ -- because we don't bind | as explained in+ -- any skolem variables here | Note [Wrapping failing kind equalities] ; emitImplication implic ; failM } Just (simples, holes)@@ -403,13 +410,31 @@ * Right here in simplifyAndEmitFlatConstraints, use buildTvImplication to wrap the failing constraint in a degenerate implication (no- skolems, no theta, no bumped TcLevel), with ic_binds = CoEvBindsVar.- That way any failing equalities will lead to an error not a warning,- irrespective of -fdefer-type-errors.+ skolems, no theta), with ic_binds = CoEvBindsVar. This setting of+ `ic_binds` means that any failing equalities will lead to an+ error not a warning, irrespective of -fdefer-type-errors: see+ Note [Failing equalities with no evidence bindings] in GHC.Tc.Errors,+ and `maybeSwitchOffDefer` in that module. - This is a slight hack, because the implication doesn't have a bumped- TcLevel, but that doesn't matter.+ We still take care to bump the TcLevel of the implication. Partly,+ that ensures that nested implications have increasing level numbers+ which seems nice. But more specifically, suppose the outer level+ has a Given `(C ty)`, which has pending (not-yet-expanded)+ superclasses. Consider what happens when we process this implication+ constraint (which we have re-emitted) in that context:+ - in the inner implication we'll call `getPendingGivenScs`,+ - we /do not/ want to get the `(C ty)` from the outer level,+ lest we try to add an evidence term for the superclass,+ which we can't do because we have specifically set+ `ic_binds` = `CoEvBindsVar`.+ - as `getPendingGivenSCcs is careful to only get Givens from+ the /current/ level, and we bumped the `TcLevel` of the implication,+ we're OK. + TL;DR: bump the `TcLevel` when creating the nested implication.+ If we don't we get a panic in `GHC.Tc.Utils.Monad.addTcEvBind` (#20043).++ We re-emit the implication rather than reporting the errors right now, so that the error mesages are improved by other solving and defaulting. e.g. we prefer@@ -1027,7 +1052,7 @@ , pred <- sig_inst_theta sig ] ; dep_vars <- candidateQTyVarsOfTypes (psig_tv_tys ++ psig_theta ++ map snd name_taus)- ; qtkvs <- quantifyTyVars dep_vars+ ; qtkvs <- quantifyTyVars allVarsOfKindDefault dep_vars ; traceTc "simplifyInfer: empty WC" (ppr name_taus $$ ppr qtkvs) ; return (qtkvs, [], emptyTcEvBinds, False) } @@ -1479,7 +1504,10 @@ | tv `elemVarSet` mono_tvs = return False | otherwise- = defaultTyVar (not poly_kinds && is_kind_var) tv+ = defaultTyVar+ (if not poly_kinds && is_kind_var then DefaultKinds else Don'tDefaultKinds)+ allVarsOfKindDefault+ tv simplify_cand candidates = do { clone_wanteds <- newWanteds DefaultOrigin candidates@@ -1539,7 +1567,7 @@ , text "grown_tcvs =" <+> ppr grown_tcvs , text "dvs =" <+> ppr dvs_plus]) - ; quantifyTyVars dvs_plus }+ ; quantifyTyVars allVarsOfKindDefault dvs_plus } ------------------ growThetaTyVars :: ThetaType -> TyCoVarSet -> TyCoVarSet@@ -2374,6 +2402,11 @@ = do { traceTcS "defaultTyVarTcS RuntimeRep" (ppr the_tv) ; unifyTyVar the_tv liftedRepTy ; return True }+ | isLevityVar the_tv+ , not (isTyVarTyVar the_tv)+ = do { traceTcS "defaultTyVarTcS Levity" (ppr the_tv)+ ; unifyTyVar the_tv liftedDataConTy+ ; return True } | isMultiplicityVar the_tv , not (isTyVarTyVar the_tv) -- TyVarTvs should only be unified with a tyvar -- never with a type; c.f. TcMType.defaultTyVar@@ -2568,6 +2601,17 @@ = do { info@(default_tys, _) <- getDefaultInfo ; wanteds <- TcS.zonkWC wanteds + ; tcg_env <- TcS.getGblEnv+ ; let plugins = tcg_defaulting_plugins tcg_env++ ; plugin_defaulted <- if null plugins then return [] else+ do {+ ; traceTcS "defaultingPlugins {" (ppr wanteds)+ ; defaultedGroups <- mapM (run_defaulting_plugin wanteds) plugins+ ; traceTcS "defaultingPlugins }" (ppr defaultedGroups)+ ; return defaultedGroups+ }+ ; let groups = findDefaultableGroups info wanteds ; traceTcS "applyDefaultingRules {" $@@ -2579,8 +2623,21 @@ ; traceTcS "applyDefaultingRules }" (ppr something_happeneds) - ; return (or something_happeneds) }+ ; return $ or something_happeneds || or plugin_defaulted }+ where run_defaulting_plugin wanteds p =+ do { groups <- runTcPluginTcS (p wanteds)+ ; defaultedGroups <-+ filterM (\g -> disambigGroup+ (deProposalCandidates g)+ (deProposalTyVar g, deProposalCts g))+ groups+ ; traceTcS "defaultingPlugin " $ ppr defaultedGroups+ ; case defaultedGroups of+ [] -> return False+ _ -> return True+ } + findDefaultableGroups :: ( [Type] , (Bool,Bool) ) -- (Overloaded strings, extended default rules)@@ -2641,8 +2698,7 @@ ------------------------------ disambigGroup :: [Type] -- The default types- -> (TcTyVar, [Ct]) -- All classes of the form (C a)- -- sharing same type variable+ -> (TcTyVar, [Ct]) -- All constraints sharing same type variable -> TcS Bool -- True <=> something happened, reflected in ty_binds disambigGroup [] _@@ -2656,7 +2712,7 @@ ; if success then -- Success: record the type variable binding, and return do { unifyTyVar the_tv default_ty- ; wrapWarnTcS $ warnDefaulting wanteds default_ty+ ; wrapWarnTcS $ warnDefaulting the_tv wanteds default_ty ; traceTcS "disambigGroup succeeded }" (ppr default_ty) ; return True } else@@ -2670,7 +2726,8 @@ = do { lcl_env <- TcS.getLclEnv ; tc_lvl <- TcS.getTcLevel ; let loc = mkGivenLoc tc_lvl UnkSkol lcl_env- ; wanted_evs <- mapM (newWantedEvVarNC loc . substTy subst . ctPred)+ -- Equality constraints are possible due to type defaulting plugins+ ; wanted_evs <- mapM (newWantedNC loc . substTy subst . ctPred) wanteds ; fmap isEmptyWC $ solveSimpleWanteds $ listToBag $
compiler/GHC/Tc/Solver/Canonical.hs view
@@ -15,6 +15,7 @@ import GHC.Tc.Types.Constraint import GHC.Core.Predicate import GHC.Tc.Types.Origin+import GHC.Tc.Utils.Concrete ( newConcretePrimWanted ) import GHC.Tc.Utils.Unify import GHC.Tc.Utils.TcType import GHC.Core.Type@@ -41,6 +42,7 @@ import GHC.Utils.Panic import GHC.Utils.Panic.Plain import GHC.Builtin.Types ( anyTypeOfKind )+import GHC.Builtin.Types.Prim ( concretePrimTyCon ) import GHC.Types.Name.Set import GHC.Types.Name.Reader import GHC.Hs.Type( HsIPName(..) )@@ -97,6 +99,9 @@ canonicalize (CQuantCan (QCI { qci_ev = ev, qci_pend_sc = pend_sc })) = canForAll ev pend_sc +canonicalize (CSpecialCan { cc_ev = ev, cc_special_pred = special_pred, cc_xi = xi })+ = canSpecial ev special_pred xi+ canonicalize (CIrredCan { cc_ev = ev }) = canNC ev -- Instead of rewriting the evidence before classifying, it's possible we@@ -131,6 +136,8 @@ canIrred ev ForAllPred tvs th p -> do traceTcS "canEvNC:forall" (ppr pred) canForAllNC ev tvs th p+ SpecialPred tc ty -> do traceTcS "canEvNC:special" (ppr pred)+ canSpecial ev tc ty where pred = ctEvPred ev @@ -208,7 +215,7 @@ -- Precondition: EvVar is class evidence canClass ev cls tys pend_sc fds- = -- all classes do *nominal* matching+ = -- all classes do *nominal* matching assertPpr (ctEvRole ev == Nominal) (ppr ev $$ ppr cls $$ ppr tys) $ do { redns@(Reductions _ xis) <- rewriteArgsNom ev cls_tc tys ; let redn@(Reduction _ xi) = mkClassPredRedn cls redns@@ -718,12 +725,19 @@ -- that the IrredPred branch stops work ; case classifyPredType (ctEvPred new_ev) of ClassPred cls tys -> canClassNC new_ev cls tys- EqPred eq_rel ty1 ty2 -> canEqNC new_ev eq_rel ty1 ty2+ EqPred eq_rel ty1 ty2 -> -- IrredPreds have kind Constraint, so+ -- cannot become EqPreds+ pprPanic "canIrred: EqPred"+ (ppr ev $$ ppr eq_rel $$ ppr ty1 $$ ppr ty2) ForAllPred tvs th p -> -- this is highly suspect; Quick Look -- should never leave a meta-var filled -- in with a polytype. This is #18987. do traceTcS "canEvNC:forall" (ppr pred) canForAllNC ev tvs th p+ SpecialPred tc tys -> -- IrredPreds have kind Constraint, so cannot+ -- become SpecialPreds+ pprPanic "canIrred: SpecialPred"+ (ppr ev $$ ppr tc $$ ppr tys) IrredPred {} -> continueWith $ mkIrredCt IrredShapeReason new_ev } } @@ -896,6 +910,133 @@ ************************************************************************+* *+* Special predicates+* *+********************************************************************* -}++-- | Canonicalise a 'SpecialPred' constraint.+canSpecial :: CtEvidence -> SpecialPred -> TcType -> TcS (StopOrContinue Ct)+canSpecial ev special_pred ty+ = do { -- Special constraints should never appear in Givens.+ ; massertPpr (not $ isGivenOrigin $ ctEvOrigin ev)+ (text "canSpecial: Given Special constraint" $$ ppr ev)+ ; case special_pred of+ { ConcretePrimPred -> canConcretePrim ev ty } }++{- Note [Canonical Concrete# constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A 'Concrete#' constraint can be decomposed precisely when+it is an application, possibly nullary, of a concrete 'TyCon'.++A canonical 'Concrete#' constraint is one that cannot be decomposed.++To illustrate, when we come across a constraint of the form `Concrete# (f a_1 ... a_n)`,+to canonicalise it, we decompose it into the collection of constraints+`Concrete# a_1`, ..., `Concrete# a_n`, whenever `f` is a concrete type constructor+(that is, it is not a type variable, nor a type-family, nor an abstract 'TyCon'+as declared in a Backpack signature file).++Writing NC for a non-canonical constraint and C for a canonical one,+here are some examples:++ (1)+ NC: Concrete# IntRep+ ==> nullary decomposition, by observing that `IntRep = TyConApp intRepTyCon []`++ (2)+ NC: Concrete# (TYPE (TupleRep '[Rep, rr])) -- where 'Rep' is an abstract type and 'rr' is a type variable+ ==> decompose once, noting that 'TYPE' is a concrete 'TyCon'+ NC: Concrete# (TupleRep '[Rep, rr])+ ==> decompose again in the same way but with 'TupleRep'+ NC: Concrete# ((:) @RuntimeRep Rep ((:) @RuntimeRep rr []))+ ==> handle (:) and its type-level argument 'RuntimeRep' (which is concrete)+ C: Concrete# Rep, NC: Concrete# ((:) @RuntimeRep rr []))+ ==> the second constraint can be decomposed again; 'RuntimeRep' and '[]' are concrete, so we get+ C: Concrete# Rep, C: Concrete# rr++-}++-- | Canonicalise a 'Concrete#' constraint.+--+-- See Note [Canonical Concrete# constraints] for details.+canConcretePrim :: CtEvidence -> TcType -> TcS (StopOrContinue Ct)+canConcretePrim ev ty+ = do {+ -- As per Note [The Concrete mechanism] in GHC.Tc.Instance.Class,+ -- in PHASE 1, we don't allow a 'Concrete#' constraint to be rewritten.+ -- We still need to zonk, otherwise we can end up stuck with a constraint+ -- such as `Concrete# rep` for a unification variable `rep`,+ -- which we can't make progress on.+ ; ty <- zonkTcType ty+ ; traceTcS "canConcretePrim" $+ vcat [text "ev =" <+> ppr ev, text "ty =" <+> ppr ty]++ ; decomposeConcretePrim ev ty }++-- | Try to decompose a 'Concrete#' constraint:+--+-- - calls 'canDecomposableConcretePrim' if the constraint can be decomposed;+-- - calls 'canNonDecomposableConcretePrim' otherwise.+decomposeConcretePrim :: CtEvidence -> Type -> TcS (StopOrContinue Ct)+decomposeConcretePrim ev ty+ -- Handle applications of concrete 'TyCon's.+ -- See examples (1,2) in Note [Canonical Concrete# constraints].+ | (f,args) <- tcSplitAppTys ty+ , Just f_tc <- tyConAppTyCon_maybe f+ , isConcreteTyCon f_tc+ = canDecomposableConcretePrim ev f_tc args++ -- Couldn't decompose the constraint: keep it as-is.+ | otherwise+ = canNonDecomposableConcretePrim ev ty++-- | Decompose a constraint of the form @'Concrete#' (f t_1 ... t_n)@,+-- for a concrete `TyCon' `f`.+--+-- This function will emit new Wanted @Concrete# t_i@ constraints, one for+-- each of the arguments of `f`.+--+-- See Note [Canonical Concrete# constraints].+canDecomposableConcretePrim :: CtEvidence+ -> TyCon+ -> [TcType]+ -> TcS (StopOrContinue Ct)+canDecomposableConcretePrim ev f_tc args+ = do { traceTcS "canDecomposableConcretePrim" $+ vcat [text "args =" <+> ppr args, text "ev =" <+> ppr ev]+ ; arg_cos <- mapM (emit_new_concretePrim_wanted (ctEvLoc ev)) args+ ; case ev of+ CtWanted { ctev_dest = dest }+ -> setWantedEvTerm dest (evCoercion $ mkTyConAppCo Nominal f_tc arg_cos)+ _ -> pprPanic "canDecomposableConcretePrim: non-Wanted" $+ vcat [ text "ev =" <+> ppr ev+ , text "args =" <+> ppr args ]+ ; stopWith ev "Decomposed Concrete#" }++-- | Canonicalise a non-decomposable 'Concrete#' constraint.+canNonDecomposableConcretePrim :: CtEvidence -> TcType -> TcS (StopOrContinue Ct)+canNonDecomposableConcretePrim ev ty+ = do { -- Update the evidence to account for the zonk to `ty`.+ let ki = typeKind ty+ new_ev = ev { ctev_pred = mkTyConApp concretePrimTyCon [ki, ty] }+ new_ct =+ CSpecialCan { cc_ev = new_ev+ , cc_special_pred = ConcretePrimPred+ , cc_xi = ty }+ ; traceTcS "canNonDecomposableConcretePrim" $+ vcat [ text "ty =" <+> ppr ty, text "new_ev =" <+> ppr new_ev ]+ ; continueWith new_ct }++-- | Create a new 'Concrete#' Wanted constraint and immediately add it+-- to the work list.+emit_new_concretePrim_wanted :: CtLoc -> Type -> TcS Coercion+emit_new_concretePrim_wanted loc ty+ = do { (hole, wanted) <- wrapTcS $ newConcretePrimWanted loc ty+ ; emitWorkNC [wanted]+ ; return $ mkHoleCo hole }++{- ********************************************************************** * * * Equalities * *
compiler/GHC/Tc/Solver/Interact.hs view
@@ -1,5 +1,4 @@ - {-# OPTIONS_GHC -Wno-incomplete-record-updates #-} {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} @@ -431,9 +430,10 @@ = do { inerts <- getTcSInerts ; let ics = inert_cans inerts ; case wi of- CEqCan {} -> interactEq ics wi- CIrredCan {} -> interactIrred ics wi- CDictCan {} -> interactDict ics wi+ CEqCan {} -> interactEq ics wi+ CIrredCan {} -> interactIrred ics wi+ CDictCan {} -> interactDict ics wi+ CSpecialCan {} -> continueWith wi -- cannot have Special Givens, so nothing to interact with _ -> pprPanic "interactWithInerts" (ppr wi) } -- CNonCanonical have been canonicalised @@ -1573,7 +1573,7 @@ interactEq _ wi = pprPanic "interactEq" (ppr wi) ------------------------- We have a meta-tyvar on the left, and metaTyVarUpateOK has said "yes"+-- We have a meta-tyvar on the left, and metaTyVarUpdateOK has said "yes" -- So try to solve by unifying. -- Three reasons why not: -- Skolem escape@@ -1905,14 +1905,24 @@ topReactionsStage work_item = do { traceTcS "doTopReact" (ppr work_item) ; case work_item of- CDictCan {} -> do { inerts <- getTcSInerts- ; doTopReactDict inerts work_item }- CEqCan {} -> doTopReactEq work_item- CIrredCan {} -> doTopReactOther work_item- _ -> -- Any other work item does not react with any top-level equations- continueWith work_item } + CDictCan {} ->+ do { inerts <- getTcSInerts+ ; doTopReactDict inerts work_item } + CEqCan {} ->+ doTopReactEq work_item++ CSpecialCan {} ->+ -- No top-level interactions for special constraints.+ continueWith work_item++ CIrredCan {} ->+ doTopReactOther work_item++ -- Any other work item does not react with any top-level equations+ _ -> continueWith work_item }+ -------------------- doTopReactOther :: Ct -> TcS (StopOrContinue Ct) -- Try local quantified constraints for@@ -1938,6 +1948,12 @@ ev = ctEvidence work_item loc = ctEvLoc ev pred = ctEvPred ev++{-********************************************************************+* *+ Top-level reaction for equality constraints (CEqCan)+* *+********************************************************************-} doTopReactEqPred :: Ct -> EqRel -> TcType -> TcType -> TcS (StopOrContinue Ct) doTopReactEqPred work_item eq_rel t1 t2
compiler/GHC/Tc/Solver/Monad.hs view
@@ -13,9 +13,8 @@ module GHC.Tc.Solver.Monad ( -- The TcS monad- TcS, runTcS, runTcSDeriveds, runTcSWithEvBinds, runTcSInerts,- failTcS, warnTcS, addErrTcS, wrapTcS,- runTcSEqualities,+ TcS, runTcS, runTcSDeriveds, runTcSDerivedsEarlyAbort, runTcSWithEvBinds,+ runTcSInerts, failTcS, warnTcS, addErrTcS, wrapTcS, runTcSEqualities, nestTcS, nestImplicTcS, setEvBindsTcS, emitImplicationTcS, emitTvImplicationTcS, @@ -160,6 +159,7 @@ import GHC.Utils.Outputable import GHC.Utils.Panic import GHC.Utils.Logger+import GHC.Utils.Misc (HasDebugCallStack) import GHC.Data.Bag as Bag import GHC.Types.Unique.Supply import GHC.Tc.Types@@ -614,10 +614,11 @@ addInertCan :: Ct -> TcS () -- Precondition: item /is/ canonical -- See Note [Adding an equality to the InertCans]-addInertCan ct- = do { traceTcS "addInertCan {" $+addInertCan ct =+ do { traceTcS "addInertCan {" $ text "Trying to insert new inert item:" <+> ppr ct-+ ; mkTcS (\TcSEnv{tcs_abort_on_insoluble=abort_flag} ->+ when (abort_flag && insolubleEqCt ct) TcM.failM) ; ics <- getInertCans ; ct <- maybeEmitShadow ics ct ; ics <- maybeKickOut ics ct@@ -729,7 +730,7 @@ -------------- addInertSafehask :: InertCans -> Ct -> InertCans addInertSafehask ics item@(CDictCan { cc_class = cls, cc_tyargs = tys })- = ics { inert_safehask = addDictCt (inert_dicts ics) cls tys item }+ = ics { inert_safehask = addDictCt (inert_dicts ics) (classTyCon cls) tys item } addInertSafehask _ item = pprPanic "addInertSafehask: can't happen! Inserting " $ ppr item@@ -767,7 +768,6 @@ = updInertTcS $ \ ics -> ics { inert_solved_dicts = solved_dicts } - {- ********************************************************************* * * Other inert-set operations@@ -878,7 +878,7 @@ add :: Ct -> DictMap Ct -> DictMap Ct add ct@(CDictCan { cc_class = cls, cc_tyargs = tys }) dicts- = addDictCt dicts cls tys ct+ = addDictCt dicts (classTyCon cls) tys ct add ct _ = pprPanic "getPendingScDicts" (ppr ct) get_pending_inst :: [Ct] -> QCInst -> ([Ct], QCInst)@@ -901,21 +901,21 @@ -- (because they come from the inert set) -- the unsolved implics may not be getUnsolvedInerts- = do { IC { inert_eqs = tv_eqs- , inert_funeqs = fun_eqs- , inert_irreds = irreds- , inert_blocked = blocked- , inert_dicts = idicts+ = do { IC { inert_eqs = tv_eqs+ , inert_funeqs = fun_eqs+ , inert_irreds = irreds+ , inert_blocked = blocked+ , inert_dicts = idicts } <- getInertCans - ; let unsolved_tv_eqs = foldTyEqs add_if_unsolved tv_eqs emptyCts- unsolved_fun_eqs = foldFunEqs add_if_unsolveds fun_eqs emptyCts- unsolved_irreds = Bag.filterBag is_unsolved irreds- unsolved_blocked = blocked -- all blocked equalities are W/D- unsolved_dicts = foldDicts add_if_unsolved idicts emptyCts- unsolved_others = unionManyBags [ unsolved_irreds- , unsolved_dicts- , unsolved_blocked ]+ ; let unsolved_tv_eqs = foldTyEqs add_if_unsolved tv_eqs emptyCts+ unsolved_fun_eqs = foldFunEqs add_if_unsolveds fun_eqs emptyCts+ unsolved_irreds = Bag.filterBag is_unsolved irreds+ unsolved_blocked = blocked -- all blocked equalities are W/D+ unsolved_dicts = foldDicts add_if_unsolved idicts emptyCts+ unsolved_others = unionManyBags [ unsolved_irreds+ , unsolved_dicts+ , unsolved_blocked ] ; implics <- getWorkListImplics @@ -1077,6 +1077,8 @@ CQuantCan {} -> panic "removeInertCt: CQuantCan" CIrredCan {} -> panic "removeInertCt: CIrredEvCan" CNonCanonical {} -> panic "removeInertCt: CNonCanonical"+ CSpecialCan _ special_pred _ ->+ pprPanic "removeInertCt" (ppr "CSpecialCan" <+> parens (ppr special_pred)) -- | Looks up a family application in the inerts. lookupFamAppInert :: TyCon -> [Type] -> TcS (Maybe (Reduction, CtFlavourRole))@@ -1198,6 +1200,11 @@ tcs_inerts :: IORef InertSet, -- Current inert set + -- Whether to throw an exception if we come across an insoluble constraint.+ -- Used to fail-fast when checking for hole-fits. See Note [Speeding up+ -- valid hole-fits].+ tcs_abort_on_insoluble :: Bool,+ -- See Note [WorkList priorities] in GHC.Tc.Solver.InertSet tcs_worklist :: IORef WorkList -- Current worklist }@@ -1313,6 +1320,7 @@ ; res <- runTcSWithEvBinds ev_binds_var tcs ; ev_binds <- TcM.getTcEvBindsMap ev_binds_var ; return (res, ev_binds) }+ -- | This variant of 'runTcS' will keep solving, even when only Deriveds -- are left around. It also doesn't return any evidence, as callers won't -- need it.@@ -1321,6 +1329,14 @@ = do { ev_binds_var <- TcM.newTcEvBinds ; runTcSWithEvBinds ev_binds_var tcs } ++-- | This variant of 'runTcSDeriveds' will immediatley fail upon encountering an+-- insoluble ct. See Note [Speeding up valid-hole fits]+runTcSDerivedsEarlyAbort :: TcS a -> TcM a+runTcSDerivedsEarlyAbort tcs+ = do { ev_binds_var <- TcM.newTcEvBinds+ ; runTcSWithEvBinds' True True ev_binds_var tcs }+ -- | This can deal only with equality constraints. runTcSEqualities :: TcS a -> TcM a runTcSEqualities thing_inside@@ -1332,7 +1348,7 @@ runTcSInerts :: InertSet -> TcS a -> TcM (a, InertSet) runTcSInerts inerts tcs = do ev_binds_var <- TcM.newTcEvBinds- runTcSWithEvBinds' False ev_binds_var $ do+ runTcSWithEvBinds' False False ev_binds_var $ do setTcSInerts inerts a <- tcs new_inerts <- getTcSInerts@@ -1341,27 +1357,29 @@ runTcSWithEvBinds :: EvBindsVar -> TcS a -> TcM a-runTcSWithEvBinds = runTcSWithEvBinds' True+runTcSWithEvBinds = runTcSWithEvBinds' True False runTcSWithEvBinds' :: Bool -- ^ Restore type variable cycles afterwards? -- Don't if you want to reuse the InertSet. -- See also Note [Type variable cycles] -- in GHC.Tc.Solver.Canonical+ -> Bool -> EvBindsVar -> TcS a -> TcM a-runTcSWithEvBinds' restore_cycles ev_binds_var tcs+runTcSWithEvBinds' restore_cycles abort_on_insoluble ev_binds_var tcs = do { unified_var <- TcM.newTcRef 0 ; step_count <- TcM.newTcRef 0 ; inert_var <- TcM.newTcRef emptyInert ; wl_var <- TcM.newTcRef emptyWorkList ; unif_lvl_var <- TcM.newTcRef Nothing- ; let env = TcSEnv { tcs_ev_binds = ev_binds_var- , tcs_unified = unified_var- , tcs_unif_lvl = unif_lvl_var- , tcs_count = step_count- , tcs_inerts = inert_var- , tcs_worklist = wl_var }+ ; let env = TcSEnv { tcs_ev_binds = ev_binds_var+ , tcs_unified = unified_var+ , tcs_unif_lvl = unif_lvl_var+ , tcs_count = step_count+ , tcs_inerts = inert_var+ , tcs_abort_on_insoluble = abort_on_insoluble+ , tcs_worklist = wl_var } -- Run the computation ; res <- unTcS tcs env@@ -1418,10 +1436,11 @@ -> TcLevel -> TcS a -> TcS a nestImplicTcS ref inner_tclvl (TcS thing_inside)- = TcS $ \ TcSEnv { tcs_unified = unified_var- , tcs_inerts = old_inert_var- , tcs_count = count- , tcs_unif_lvl = unif_lvl+ = TcS $ \ TcSEnv { tcs_unified = unified_var+ , tcs_inerts = old_inert_var+ , tcs_count = count+ , tcs_unif_lvl = unif_lvl+ , tcs_abort_on_insoluble = abort_on_insoluble } -> do { inerts <- TcM.readTcRef old_inert_var ; let nest_inert = inerts { inert_cycle_breakers = []@@ -1430,12 +1449,13 @@ -- All other InertSet fields are inherited ; new_inert_var <- TcM.newTcRef nest_inert ; new_wl_var <- TcM.newTcRef emptyWorkList- ; let nest_env = TcSEnv { tcs_count = count -- Inherited- , tcs_unif_lvl = unif_lvl -- Inherited- , tcs_ev_binds = ref- , tcs_unified = unified_var- , tcs_inerts = new_inert_var- , tcs_worklist = new_wl_var }+ ; let nest_env = TcSEnv { tcs_count = count -- Inherited+ , tcs_unif_lvl = unif_lvl -- Inherited+ , tcs_ev_binds = ref+ , tcs_unified = unified_var+ , tcs_inerts = new_inert_var+ , tcs_abort_on_insoluble = abort_on_insoluble+ , tcs_worklist = new_wl_var } ; res <- TcM.setTcLevel inner_tclvl $ thing_inside nest_env @@ -2007,7 +2027,7 @@ ; TcM.writeTcRef ref tcvs' } } -- | Equalities only-setWantedEq :: TcEvDest -> Coercion -> TcS ()+setWantedEq :: HasDebugCallStack => TcEvDest -> Coercion -> TcS () setWantedEq (HoleDest hole) co = do { useVars (coVarsOfCo co) ; fillCoercionHole hole co }
compiler/GHC/Tc/TyCl.hs view
@@ -33,7 +33,7 @@ import GHC.Hs -import GHC.Tc.Errors.Types ( TcRnMessage(..), LevityCheckProvenance(..) )+import GHC.Tc.Errors.Types ( TcRnMessage(..), FixedRuntimeRepProvenance(..) ) import GHC.Tc.TyCl.Build import GHC.Tc.Solver( pushLevelAndSolveEqualities, pushLevelAndSolveEqualitiesX , reportUnsolvedEqualities )@@ -907,7 +907,7 @@ -- Step 2b: quantify, mainly meaning skolemise the free variables -- Returned 'inferred' are scope-sorted and skolemised- ; inferred <- quantifyTyVars dvs2+ ; inferred <- quantifyTyVars allVarsOfKindDefault dvs2 ; traceTc "generaliseTcTyCon: pre zonk" (vcat [ text "tycon =" <+> ppr tc@@ -2701,7 +2701,7 @@ , fdInjectivityAnn = inj }) | DataFamily <- fam_info = bindTyClTyVars tc_name $ \ _ binders res_kind -> do- { traceTc "data family:" (ppr tc_name)+ { traceTc "tcFamDecl1 data family:" (ppr tc_name) ; checkFamFlag tc_name -- Check that the result kind is OK@@ -2727,7 +2727,7 @@ | OpenTypeFamily <- fam_info = bindTyClTyVars tc_name $ \ _ binders res_kind -> do- { traceTc "open type family:" (ppr tc_name)+ { traceTc "tcFamDecl1 open type family:" (ppr tc_name) ; checkFamFlag tc_name ; inj' <- tcInjectivity binders inj ; checkResultSigFlag tc_name sig -- check after injectivity for better errors@@ -2739,7 +2739,7 @@ | ClosedTypeFamily mb_eqns <- fam_info = -- Closed type families are a little tricky, because they contain the definition -- of both the type family and the equations for a CoAxiom.- do { traceTc "Closed type family:" (ppr tc_name)+ do { traceTc "tcFamDecl1 Closed type family:" (ppr tc_name) -- the variables in the header scope only over the injectivity -- declaration but this is not involved here ; (inj', binders, res_kind)@@ -2955,21 +2955,21 @@ mk_permissive_kind HsigFile [] = True mk_permissive_kind _ _ = False - -- In hs-boot, a 'data' declaration with no constructors+ -- In an hs-boot or a signature file,+ -- a 'data' declaration with no constructors -- indicates a nominally distinct abstract data type.- mk_tc_rhs HsBootFile _ []- = return AbstractTyCon-- mk_tc_rhs HsigFile _ [] -- ditto+ mk_tc_rhs (isHsBootOrSig -> True) _ [] = return AbstractTyCon mk_tc_rhs _ tycon data_cons = case new_or_data of- DataType -> return (mkDataTyConRhs data_cons)+ DataType -> return $+ mkLevPolyDataTyConRhs+ (isFixedRuntimeRepKind (tyConResKind tycon))+ data_cons NewType -> assert (not (null data_cons)) $ mkNewTyConRhs tc_name tycon (head data_cons) - ------------------------- kcTyFamInstEqn :: TcTyCon -> LTyFamInstEqn GhcRn -> TcM () -- Used for the equations of a closed type family only@@ -2985,32 +2985,19 @@ , text "fam_tc =" <+> ppr tc_fam_tc <+> dcolon <+> ppr (tyConKind tc_fam_tc) , text "feqn_bndrs =" <+> ppr outer_bndrs , text "feqn_pats =" <+> ppr hs_pats ])- -- this check reports an arity error instead of a kind error; easier for user- ; let vis_pats = numVisibleArgs hs_pats - -- First, check if we're dealing with a closed type family equation, and- -- if so, ensure that each equation's type constructor is for the right- -- type family. E.g. barf on- -- type family F a where { G Int = Bool }- ; checkTc (tc_fam_tc_name == eqn_tc_name) $- wrongTyFamName tc_fam_tc_name eqn_tc_name-- ; checkTc (vis_pats == vis_arity) $- wrongNumberOfParmsErr vis_arity+ ; checkTyFamInstEqn tc_fam_tc eqn_tc_name hs_pats ; discardResult $ bindOuterFamEqnTKBndrs_Q_Tv outer_bndrs $ do { (_fam_app, res_kind) <- tcFamTyPats tc_fam_tc hs_pats ; tcCheckLHsType hs_rhs_ty (TheKind res_kind) }- -- Why "_Tv" here? Consider (#14066+ -- Why "_Tv" here? Consider (#14066) -- type family Bar x y where -- Bar (x :: a) (y :: b) = Int -- Bar (x :: c) (y :: d) = Bool -- During kind-checking, a,b,c,d should be TyVarTvs and unify appropriately }- where- vis_arity = length (tyConVisibleTyVars tc_fam_tc)- tc_fam_tc_name = getName tc_fam_tc -------------------------- tcTyFamInstEqn :: TcTyCon -> AssocInstInfo -> LTyFamInstEqn GhcRn@@ -3019,7 +3006,8 @@ -- (typechecked here) have TyFamInstEqns tcTyFamInstEqn fam_tc mb_clsinfo- (L loc (FamEqn { feqn_bndrs = outer_bndrs+ (L loc (FamEqn { feqn_tycon = L _ eqn_tc_name+ , feqn_bndrs = outer_bndrs , feqn_pats = hs_pats , feqn_rhs = hs_rhs_ty })) = setSrcSpanA loc $@@ -3030,15 +3018,8 @@ NotAssociated {} -> empty InClsInst { ai_class = cls } -> text "class" <+> ppr cls <+> pprTyVars (classTyVars cls) ] - -- First, check the arity of visible arguments- -- If we wait until validity checking, we'll get kind errors- -- below when an arity error will be much easier to understand.- -- Note that for closed type families, kcTyFamInstEqn has already- -- checked the arity previously.- ; let vis_arity = length (tyConVisibleTyVars fam_tc)- vis_pats = numVisibleArgs hs_pats- ; checkTc (vis_pats == vis_arity) $- wrongNumberOfParmsErr vis_arity+ ; checkTyFamInstEqn fam_tc eqn_tc_name hs_pats+ ; (qtvs, pats, rhs_ty) <- tcTyFamInstEqnGuts fam_tc mb_clsinfo outer_bndrs hs_pats hs_rhs_ty -- Don't print results they may be knot-tied@@ -3047,6 +3028,24 @@ (map (const Nominal) qtvs) (locA loc)) } +checkTyFamInstEqn :: TcTyCon -> Name -> [HsArg tm ty] -> TcM ()+checkTyFamInstEqn tc_fam_tc eqn_tc_name hs_pats =+ do { -- Ensure that each equation's type constructor is for the right+ -- type family. E.g. barf on+ -- type family F a where { G Int = Bool }+ let tc_fam_tc_name = getName tc_fam_tc+ ; checkTc (tc_fam_tc_name == eqn_tc_name) $+ wrongTyFamName tc_fam_tc_name eqn_tc_name++ -- Check the arity of visible arguments+ -- If we wait until validity checking, we'll get kind errors+ -- below when an arity error will be much easier to understand.+ ; let vis_arity = length (tyConVisibleTyVars tc_fam_tc)+ vis_pats = numVisibleArgs hs_pats+ ; checkTc (vis_pats == vis_arity) $+ wrongNumberOfParmsErr vis_arity+ }+ {- Note [Instantiating a family tycon] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It's possible that kind-checking the result of a family tycon applied to@@ -3141,7 +3140,7 @@ -- See Note [Generalising in tcTyFamInstEqnGuts] ; dvs <- candidateQTyVarsOfTypes (lhs_ty : mkTyVarTys outer_tvs)- ; qtvs <- quantifyTyVars dvs+ ; qtvs <- quantifyTyVars noVarsOfKindDefault dvs ; reportUnsolvedEqualities FamInstSkol qtvs tclvl wanted ; checkFamTelescope tclvl outer_hs_bndrs outer_tvs @@ -4373,10 +4372,11 @@ -- If we are dealing with a newtype, we allow representation -- polymorphism regardless of whether or not UnliftedNewtypes -- is enabled. A later check in checkNewDataCon handles this,- -- producing a better error message than checkForLevPoly would.+ -- producing a better error message than checkTypeHasFixedRuntimeRep would. ; unless (isNewTyCon tc) $ checkNoErrs $- mapM_ (checkForLevPoly LevityCheckInValidDataCon) (map scaledThing $ dataConOrigArgTys con)+ mapM_ (checkTypeHasFixedRuntimeRep FixedRuntimeRepDataConField)+ (map scaledThing $ dataConOrigArgTys con) -- the checkNoErrs is to prevent a panic in isVanillaDataCon -- (called a a few lines down), which can fall over if there is a -- bang on a representation-polymorphic argument. This is #18534,@@ -4588,12 +4588,11 @@ -- newBoard :: MonadState b m => m () -- Here, MonadState has a fundep m->b, so newBoard is fine - -- a method cannot be representation-polymorphic, as we have to- -- store the method in a dictionary- -- example of what this prevents:- -- class BoundedX (a :: TYPE r) where minBound :: a- -- See Note [Representation polymorphism checking] in GHC.HsToCore.Monad- ; checkForLevPoly LevityCheckInValidClass tau1+ -- NB: we don't check that the class method is not representation-polymorphic here,+ -- as GHC.TcGen.TyCl.tcClassSigType already includes a subtype check that guarantees+ -- typeclass methods always have kind 'Type'.+ --+ -- Test case: rep-poly/RepPolyClassMethod. ; unless constrained_class_methods $ mapM_ check_constraint (tail (cls_pred:op_theta))
compiler/GHC/Tc/TyCl/Build.hs view
@@ -52,11 +52,11 @@ = do { co_tycon_name <- newImplicitBinder tycon_name mkNewTyCoOcc ; let nt_ax = mkNewTypeCoAxiom co_tycon_name tycon etad_tvs etad_roles etad_rhs ; traceIf (text "mkNewTyConRhs" <+> ppr nt_ax)- ; return (NewTyCon { data_con = con,- nt_rhs = rhs_ty,- nt_etad_rhs = (etad_tvs, etad_rhs),- nt_co = nt_ax,- nt_lev_poly = isKindLevPoly res_kind } ) }+ ; return (NewTyCon { data_con = con,+ nt_rhs = rhs_ty,+ nt_etad_rhs = (etad_tvs, etad_rhs),+ nt_co = nt_ax,+ nt_fixed_rep = isFixedRuntimeRepKind res_kind } ) } -- Coreview looks through newtypes with a Nothing -- for nt_co, or uses explicit coercions otherwise where@@ -292,7 +292,8 @@ ; tc_rep_name <- newTyConRepName tycon_name ; let univ_tvs = binderVars binders tycon = mkClassTyCon tycon_name binders roles- AbstractTyCon rec_clas tc_rep_name+ AbstractTyCon+ rec_clas tc_rep_name result = mkAbstractClass tycon_name univ_tvs fds tycon ; traceIf (text "buildClass" <+> ppr tycon) ; return result }
compiler/GHC/Tc/TyCl/Instance.hs view
@@ -750,7 +750,10 @@ ; rep_tc_name <- newFamInstTyConName lfam_name pats ; axiom_name <- newFamInstAxiomName lfam_name [pats] ; tc_rhs <- case new_or_data of- DataType -> return (mkDataTyConRhs data_cons)+ DataType -> return $+ mkLevPolyDataTyConRhs+ (isFixedRuntimeRepKind final_res_kind)+ data_cons NewType -> assert (not (null data_cons)) $ mkNewTyConRhs rep_tc_name rec_rep_tc (head data_cons) @@ -912,7 +915,7 @@ -- See GHC.Tc.TyCl Note [Generalising in tcFamTyPatsGuts] ; dvs <- candidateQTyVarsOfTypes (lhs_ty : mkTyVarTys scoped_tvs)- ; qtvs <- quantifyTyVars dvs+ ; qtvs <- quantifyTyVars noVarsOfKindDefault dvs ; reportUnsolvedEqualities FamInstSkol qtvs tclvl wanted -- Zonk the patterns etc into the Type world@@ -1333,8 +1336,9 @@ where con_app = mkLams dfun_bndrs $ mkApps (Var (dataConWrapId dict_con)) dict_args- -- mkApps is OK because of the checkForLevPoly call in checkValidClass- -- See Note [Representation polymorphism checking] in GHC.HsToCore.Monad+ -- This application will satisfy the Core invariants+ -- from Note [Representation polymorphism invariants] in GHC.Core,+ -- because typeclass method types are never unlifted. dict_args = map Type inst_tys ++ [mkVarApps (Var id) dfun_bndrs | id <- sc_meth_ids]
compiler/GHC/Tc/Utils/Backpack.hs view
@@ -4,9 +4,7 @@ {-# LANGUAGE TypeFamilies #-} module GHC.Tc.Utils.Backpack (- findExtraSigImports', findExtraSigImports,- implicitRequirements', implicitRequirements, implicitRequirementsShallow, checkUnit,@@ -40,6 +38,7 @@ import GHC.Types.Var import GHC.Types.Unique.DSet import GHC.Types.Name.Shape+import GHC.Types.PkgQual import GHC.Unit import GHC.Unit.Finder@@ -278,50 +277,33 @@ -- process A first, because the merging process will cause B to indirectly -- import A. This function finds the TRANSITIVE closure of all such imports -- we need to make.-findExtraSigImports' :: HscEnv- -> HscSource- -> ModuleName- -> IO (UniqDSet ModuleName)-findExtraSigImports' hsc_env HsigFile modname =- fmap unionManyUniqDSets (forM reqs $ \(Module iuid mod_name) ->- (initIfaceLoad hsc_env+findExtraSigImports :: HscEnv+ -> HscSource+ -> ModuleName+ -> IO [ModuleName]+findExtraSigImports hsc_env HsigFile modname = do+ let+ dflags = hsc_dflags hsc_env+ ctx = initSDocContext dflags defaultUserStyle+ unit_state = hsc_units hsc_env+ reqs = requirementMerges unit_state modname+ holes <- forM reqs $ \(Module iuid mod_name) -> do+ initIfaceLoad hsc_env . withException ctx $ moduleFreeHolesPrecise (text "findExtraSigImports")- (mkModule (VirtUnit iuid) mod_name)))- where- dflags = hsc_dflags hsc_env- ctx = initSDocContext dflags defaultUserStyle- unit_state = hsc_units hsc_env- reqs = requirementMerges unit_state modname--findExtraSigImports' _ _ _ = return emptyUniqDSet---- | 'findExtraSigImports', but in a convenient form for "GHC.Driver.Make" and--- "GHC.Tc.Module".-findExtraSigImports :: HscEnv -> HscSource -> ModuleName- -> IO [(Maybe FastString, Located ModuleName)]-findExtraSigImports hsc_env hsc_src modname = do- extra_requirements <- findExtraSigImports' hsc_env hsc_src modname- return [ (Nothing, noLoc mod_name)- | mod_name <- uniqDSetToList extra_requirements ]+ (mkModule (VirtUnit iuid) mod_name)+ return (uniqDSetToList (unionManyUniqDSets holes)) --- A version of 'implicitRequirements'' which is more friendly--- for "GHC.Tc.Module".-implicitRequirements :: HscEnv- -> [(Maybe FastString, Located ModuleName)]- -> IO [(Maybe FastString, Located ModuleName)]-implicitRequirements hsc_env normal_imports- = do mns <- implicitRequirements' hsc_env normal_imports- return [ (Nothing, noLoc mn) | mn <- mns ]+findExtraSigImports _ _ _ = return [] -- Given a list of 'import M' statements in a module, figure out -- any extra implicit requirement imports they may have. For -- example, if they 'import M' and M resolves to p[A=<B>,C=D], then -- they actually also import the local requirement B.-implicitRequirements' :: HscEnv- -> [(Maybe FastString, Located ModuleName)]+implicitRequirements :: HscEnv+ -> [(PkgQual, Located ModuleName)] -> IO [ModuleName]-implicitRequirements' hsc_env normal_imports+implicitRequirements hsc_env normal_imports = fmap concat $ forM normal_imports $ \(mb_pkg, L _ imp) -> do found <- findImportedModule fc fopts units home_unit imp mb_pkg@@ -342,7 +324,7 @@ -- than a transitive closure done here) all the free holes are still reachable. implicitRequirementsShallow :: HscEnv- -> [(Maybe FastString, Located ModuleName)]+ -> [(PkgQual, Located ModuleName)] -> IO ([ModuleName], [InstantiatedUnit]) implicitRequirementsShallow hsc_env normal_imports = go ([], []) normal_imports where@@ -626,7 +608,7 @@ let insts = instUnitInsts iuid isFromSignaturePackage = let inst_uid = instUnitInstanceOf iuid- pkg = unsafeLookupUnitId unit_state (indefUnit inst_uid)+ pkg = unsafeLookupUnitId unit_state inst_uid in null (unitExposedModules pkg) -- 3(a). Rename the exports according to how the dependency -- was instantiated. The resulting export list will be accurate@@ -1076,7 +1058,7 @@ -- the local one just to get the information? Hmm... massert (isHomeModule home_unit outer_mod ) massert (isHomeUnitInstantiating home_unit)- let uid = Indefinite (homeUnitInstanceOf home_unit)+ let uid = homeUnitInstanceOf home_unit inner_mod `checkImplements` Module (mkInstantiatedUnit uid (homeUnitInstantiations home_unit))
+ compiler/GHC/Tc/Utils/Concrete.hs view
@@ -0,0 +1,521 @@+{-# LANGUAGE MultiWayIf #-}++module GHC.Tc.Utils.Concrete+ ( -- * Creating/emitting 'Concrete#' constraints+ hasFixedRuntimeRep+ , newConcretePrimWanted+ -- * HsWrapper: checking for representation-polymorphism+ , mkWpFun+ )+ where++import GHC.Prelude++import GHC.Core.Coercion+import GHC.Core.TyCo.Rep++import GHC.Tc.Utils.Monad+import GHC.Tc.Utils.TcType ( TcType, mkTyConApp )+import GHC.Tc.Utils.TcMType ( newCoercionHole, newFlexiTyVarTy )+import GHC.Tc.Types.Constraint+import GHC.Tc.Types.Evidence+import GHC.Tc.Types.Origin ( CtOrigin(..), FRROrigin(..), WpFunOrigin(..) )++import GHC.Builtin.Types ( unliftedTypeKindTyCon, liftedTypeKindTyCon )+import GHC.Builtin.Types.Prim ( concretePrimTyCon )++import GHC.Types.Basic ( TypeOrKind(KindLevel) )++import GHC.Core.Type ( isConcrete, typeKind )++{- Note [Concrete overview]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Special predicates of the form `Concrete# ty` are used+to check, in the typechecker, that certain types have a fixed runtime representation.+We give here an overview of the various moving parts, to serve+as a central point of reference for this topic.++ * Representation polymorphism+ Note [Representation polymorphism invariants] in GHC.Core+ Note [Representation polymorphism checking]++ The first note explains why we require that certain types have+ a fixed runtime representation.++ The second note details why we sometimes need a constraint to+ perform such checks in the typechecker: we might not know immediately+ whether a type has a fixed runtime representation. For example, we might+ need further unification to take place before being able to decide.+ So, instead of checking immediately, we emit a constraint.++ * What does it mean for a type to be concrete?+ Note [Concrete types]+ Note [The Concrete mechanism]++ The predicate 'Concrete# ty' is satisfied when we can produce+ a coercion++ co :: ty ~ concrete_ty++ where 'concrete_ty' consists only of concrete types (no type variables,+ no type families).++ The first note explains more precisely what it means for a type to be concrete.+ The second note explains how this relates to the `Concrete#` predicate,+ and explains that the implementation is happening in two phases (PHASE 1 and PHASE 2).+ In PHASE 1 (the current implementation) we only allow trivial evidence+ of the form `co = Refl`.++ * Fixed runtime representation vs fixed RuntimeRep+ Note [Fixed RuntimeRep]++ We currently enforce the representation-polymorphism invariants by checking+ that binders and function arguments have a "fixed RuntimeRep".+ That is, `ty :: ki` has a "fixed RuntimeRep" if we can solve `Concrete# ki`.++ This is slightly less general than we might like, as this rules out+ types with kind `TYPE (BoxedRep l)`: we know that this will be represented+ by a pointer, which should be enough to go on in many situations.++ * When do we emit 'Concrete#' constraints?+ Note [hasFixedRuntimeRep]++ We introduce 'Concrete#' constraints to satisfy the representation-polymorphism+ invariants outlined in Note [Representation polymorphism invariants] in GHC.Core,+ which mostly amounts to the following two cases:++ - checking that a binder has a fixed runtime representation,+ - checking that a function argument has a fixed runtime representation.++ The note explains precisely how we emit these 'Concrete#' constraints.++ * How do we solve Concrete# constraints?+ Note [Solving Concrete# constraints] in GHC.Tc.Instance.Class++ Concrete# constraints are solved through two mechanisms,+ which are both explained further in the note:++ - by decomposing them, e.g. `Concrete# (TYPE r)` is turned+ into `Concrete# r` (canonicalisation of `Concrete#` constraints),+ - by using 'Concrete' instances (top-level interactions).+ The note explains that the evidence we get from using such 'Concrete'+ instances can only ever be Refl, even in PHASE 2.++ * Reporting unsolved Concrete# constraints+ Note [Reporting representation-polymorphism errors] in GHC.Tc.Types.Origin++ When we emit a 'Concrete#' constraint, we also provide a 'FRROrigin'+ which gives context about the check being done. This origin gets reported+ to the user if we end up with an unsolved Wanted 'Concrete#' constraint.++Note [Representation polymorphism checking]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+According to the "Levity Polymorphism" paper (PLDI '17),+there are two places in which we must know that a type has a+fixed runtime representation, as explained in+ Note [Representation polymorphism invariants] in GHC.Core:++ I1. the type of a bound term-level variable,+ I2. the type of an argument to a function.++The paper explains the restrictions more fully, but briefly:+expressions in these contexts need to be stored in registers, and it's+hard (read: impossible) to store something that does not have a+fixed runtime representation.++In practice, we enforce these types to have a /fixed RuntimeRep/, which is slightly+stronger, as explained in Note [Fixed RuntimeRep].++There are two different ways we check whether a given type+has a fixed runtime representation, both in the typechecker:++ 1. When typechecking type declarations (e.g. datatypes, typeclass, pattern synonyms),+ under the GHC.Tc.TyCl module hierarchy.+ In these situations, we can immediately reject bad representation polymorphism.++ For instance, the following datatype declaration++ data Foo (r :: RuntimeRep) (a :: TYPE r) = Foo a++ is rejected in GHC.Tc.TyCl.checkValidDataCon upon seeing that the type 'a'+ is representation-polymorphic.++ Such checks are done using `GHC.Tc.Utils.TcMType.checkTypeHasFixedRuntimeRep`,+ with `GHC.Tc.Errors.Types.FixedRuntimeRepProvenance` describing the different+ contexts in which bad representation polymorphism can occur while validity checking.++ 2. When typechecking value-level declarations (functions, expressions, patterns, ...),+ under the GHC.Tc.Gen module hierarchy.+ In these situations, the typechecker might need to do some work to figure out+ whether a type has a fixed runtime representation or not. For instance,+ GHC might introduce a metavariable (rr :: RuntimeRep), which is only later+ (through constraint solving) discovered to be equal to FloatRep.++ This is handled by the Concrete mechanism outlined in+ Note [The Concrete mechanism] in GHC.Tc.Utils.Concrete.+ See Note [Concrete overview] in GHC.Tc.Utils.Concrete for an overview+ of the various moving parts.++ The idea is that, to guarantee that a type (rr :: RuntimeRep) is+ representation-monomorphic, we emit a 'Concrete# rr' Wanted constraint.+ If GHC can solve this constraint, it means 'rr' is monomorphic, and we+ are OK to proceed. Otherwise, we report this unsolved Wanted in the form+ of a representation-polymorphism error. The different contexts in which+ such constraints arise are enumerated in 'FRROrigin'.++Note [Concrete types]+~~~~~~~~~~~~~~~~~~~~~+Definition: a type is /concrete/+ iff it consists of a tree of concrete type constructors+ See GHC.Core.Type.isConcrete++Definition: a /concrete type constructor/ is defined by+ - a promoted data constructor+ - a class, data type or newtype+ - a primitive type like Array# or Int#+ - an abstract type as defined in a Backpack signature file+ (see Note [Synonyms implement abstract data] in GHC.Tc.Module)+ In particular, type and data families are not concrete.+ See GHC.Core.TyCon.isConcreteTyCon.++Examples of concrete types:+ Lifted, BoxedRep Lifted, TYPE (BoxedRep Lifted) are all concrete+Examples of non-concrete types+ F Int, TYPE (F Int), TYPE r, a Int+ NB: (F Int) is not concrete because F is a type function++Note [The Concrete mechanism]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+As explained in (2) in Note [Representation polymorphism checking],+to check (ty :: ki) has a fixed runtime representation,+we emit a `Concrete# ki` constraint, where++ Concrete# :: forall k. k -> TupleRep '[]++Such constraints get solved by decomposition, as per+ Note [Canonical Concrete# constraints] in GHC.Tc.Solver.Canonical.+When unsolved Wanted `Concrete#` constraints remain after typechecking,+we report them as representation-polymorphism errors, using `GHC.Tc.Types.Origin.FRROrigin`+to inform the user of the context in which a fixed-runtime-rep check arose.++--------------+-- EVIDENCE --+--------------++The evidence for a 'Concrete# ty' constraint is a nominal coercion++ co :: ty ~# concrete_ty++where 'concrete_ty' consists only of (non-synonym) type constructors and applications+(after expanding any vanilla type synonyms).++ OK:++ TYPE FloatRep+ TYPE (BoxedRep Lifted)+ Type+ TYPE (TupleRep '[ FloatRep, SumRep '[ IntRep, IntRep ] ])++ Not OK:++ Type variables:++ ty+ TYPE r+ TYPE (BoxedRep l)++ Type family applications:++ TYPE (Id FloatRep)++This is so that we can compute the 'PrimRep's needed to represent the type+using 'runtimeRepPrimRep', which expects to be able to read off the 'RuntimeRep',+as per Note [Getting from RuntimeRep to PrimRep] in GHC.Types.RepType.++Note that the evidence for a `Concrete#` constraint isn't a typeclass dictionary:+like with `(~#)`, the evidence is an (unlifted) nominal coercion, which justifies defining++ Concrete# :: forall k. k -> TYPE (TupleRep '[])++We still need a constraint that users can write in their own programs,+so much like `(~#)` and `(~)` we also define:++ Concrete :: forall k. k -> Constraint++The need for user-facing 'Concrete' constraints is detailed in+ Note [Concrete and Concrete#] in GHC.Builtin.Types.++-------------------------+-- PHASE 1 and PHASE 2 --+-------------------------++The Concrete mechanism is being implemented in two separate phases.++In PHASE 1 (currently implemented), we never allow a 'Concrete#' constraint+to be rewritten (see e.g. GHC.Tc.Solver.Canonical.canConcretePrim).+The only allowable evidence term is Refl, which forbids any program+that requires type family evaluation in order to determine that a 'RuntimeRep' is fixed.+N.B.: we do not currently check that this invariant is upheld: as we are discarding the+evidence in PHASE 1, we no longer have access to the coercion after constraint solving+(which is the point at which we would want to check that the filled in evidence is Refl).++In PHASE 2 (future work), we lift this restriction. To illustrate what this entails,+recall that the code generator needs to be able to compute 'PrimRep's, so that it+can put function arguments in the correct registers, etc.+As a result, we must insert additional casts in Core to ensure that no type family+reduction is needed to be able to compute 'PrimRep's. For example, the Core++ f = /\ ( a :: F Int ). \ ( x :: a ). some_expression++is problematic when 'F' is a type family: we don't know what runtime representation to use+for 'x', so we can't compile this function (we can't evaluate type family applications+after we are done with typechecking). Instead, we ensure the 'RuntimeRep' is always+explicitly visible:++ f = /\ ( a :: F Int ). \ ( x :: ( a |> kco ) ). some_expression++where 'kco' is the evidence for `Concrete# (F Int)`, for example if `F Int = TYPE Int#`+this would be:++ kco :: F Int ~# TYPE Int#++As `( a |> kco ) :: TYPE Int#`, the code generator knows to use a machine-sized+integer register for `x`, and all is good again.++Example test cases that require PHASE 2: T13105, T17021, T20363b.++Note [Fixed RuntimeRep]+~~~~~~~~~~~~~~~~~~~~~~~+Definition:+ a type `ty :: ki` has a /fixed RuntimeRep/+ iff we can solve `Concrete# ki`++In PHASE 1 (see Note [The Concrete mechanism]), this is equivalent to:++ a type `ty :: ki` has a /fixed RuntimeRep/+ iff `ki` is a concrete type (in the sense of Note [Concrete types]).++This definition is crafted to be useful to satisfy the invariants of+Core; see Note [Representation polymorphism invariants] in GHC.Core.++Notice that "fixed RuntimeRep" means (for now anyway) that+ * we know the runtime representation, and+ * we know the levity.++For example (ty :: TYPE (BoxedRep l)), where `l` is a levity variable+is /not/ "fixed RuntimeRep", even though it is always represented by+a heap pointer, because we don't know the levity. In due course we+will want to make finer distinctions, as explained in the paper+Kinds are Calling Conventions [ICFP'20], but this suffices for now.++Note [hasFixedRuntimeRep]+~~~~~~~~~~~~~~~~~~~~~~~~~+The 'hasFixedRuntimeRep' function is responsible for taking a type 'ty'+and emitting a 'Concrete#' constraint to ensure that 'ty' has a fixed `RuntimeRep`,+as outlined in Note [The Concrete mechanism].++To do so, we compute the kind 'ki' of 'ty' and emit a 'Concrete# ki' constraint,+which will only be solved if we can prove that 'ty' indeed has a fixed RuntimeRep.++ [Wrinkle: Typed Template Haskell]+ We don't perform any checks when type-checking a typed Template Haskell quote:+ we want to allow representation polymorphic quotes, as long as they are+ monomorphised at splice site.++ Example:++ Module1++ repPolyId :: forall r (a :: TYPE r). CodeQ (a -> a)+ repPolyId = [|| \ x -> x ||]++ Module2++ import Module1++ id1 :: Int -> Int+ id1 = $$repPolyId++ id2 :: Int# -> Int#+ id2 = $$repPolyId++ We implement this skip by inspecting the TH stage in `hasFixedRuntimeRep`.++ A better solution would be to use 'CodeC' constraints, as in the paper+ "Staging With Class", POPL 2022+ by Ningning Xie, Matthew Pickering, Andres Löh, Nicolas Wu, Jeremy Yallop, Meng Wang+ but for the moment, as we will typecheck again when splicing,+ this shouldn't cause any problems in practice. See ticket #18170.++ Test case: rep-poly/T18170a.++Note [Solving Concrete# constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The representation polymorphism checks emit 'Concrete# ty' constraints,+as explained in Note [hasFixedRuntimeRep] in GHC.Tc.Utils.Concrete.++The main mechanism through which a `Concrete# ty` constraint is solved+is to directly inspect 'ty' to check that it is a concrete type+such as 'TYPE IntRep' or `TYPE (TupleRep '[ TupleRep '[], FloatRep ])`,+and not, e.g., a skolem type variable.++There are, however, some interactions to take into account:++ 1. Decomposition.++ The solving of `Concrete#` constraints works recursively.+ For example, to solve a Wanted `Concrete# (TYPE r)` constraint,+ we decompose it, emitting a new `Concrete# @RuntimeRep r` Wanted constraint,+ and use it to solve the original `Concrete# (TYPE r)` constraint.+ This happens in the canonicaliser -- see GHC.Tc.Solver.Canonical.canDecomposableConcretePrim.++ Note that Decomposition fully solves `Concrete# ty` whenever `ty` is a+ concrete type. For example:++ Concrete# (TYPE (BoxedRep Lifted))+ ==> (decompose)+ Concrete# (BoxedRep Lifted)+ ==> (decompose)+ Concrete# Lifted+ ==> (decompose)+ <nothing, since Lifted is nullary>++ 2. Rewriting.++ In PHASE 1 (as per Note [The Concrete mechanism] in GHC.Tc.Utils.Concrete),+ we don't have to worry about a 'Concrete#' constraint being rewritten.+ We only need to zonk: if e.g. a metavariable, `alpha`, gets unified with `IntRep`,+ we should be able to solve `Concrete# alpha`.++ In PHASE 2, we will need to proceed as in GHC.Tc.Solver.Canonical.canClass:+ if we have a constraint `Concrete# (F ty1)` and a coercion witnessing the reduction of+ `F`, say `co :: F ty1 ~# ty2`, then we will solve `Concrete# (F ty1)` in terms of `Concrete# ty2`,+ by rewriting the evidence for `Concrete# ty2` using `co` (see GHC.Tc.Solver.Canonical.rewriteEvidence).++ 3. Backpack++ Abstract 'TyCon's in Backpack signature files are always considered to be concrete.+ This is because of the strong restrictions around how abstract types are allowed+ to be implemented, as laid out in Note [Synonyms implement abstract data] in GHC.Tc.Module.+ In particular, no variables or type family applications are allowed.++ Examples: backpack/should_run/T13955.bkp, rep-poly/RepPolyBackpack2.+-}++-- | A coercion hole used to store evidence for `Concrete#` constraints.+--+-- See Note [The Concrete mechanism].+type ConcreteHole = CoercionHole++-- | Evidence for a `Concrete#` constraint:+-- essentially a 'ConcreteHole' (a coercion hole) that will be filled later,+-- except:+--+-- - we might already have the evidence now; no point in creating a coercion hole+-- in that case;+-- - we sometimes skip the check entirely, e.g. in Typed Template Haskell+-- (see [Wrinkle: Typed Template Haskell] in Note [hasFixedRuntimeRep]).+data ConcreteEvidence+ = ConcreteReflEvidence+ -- ^ We have evidence right now: don't bother creating a 'ConcreteHole'.+ | ConcreteTypedTHNoEvidence+ -- ^ We don't emit 'Concrete#' constraints in Typed Template Haskell.+ -- See [Wrinkle: Typed Template Haskell] in Note [hasFixedRuntimeRep].+ | ConcreteHoleEvidence ConcreteHole+ -- ^ The general form of evidence: a 'ConcreteHole' that should be+ -- filled in later by the constraint solver, as per+ -- Note [Solving Concrete# constraints].++-- | Check that the kind of the provided type is of the form+-- @TYPE rep@ for a __fixed__ 'RuntimeRep' @rep@.+--+-- If this isn't immediately obvious, for instance if the 'RuntimeRep'+-- is hidden under a type-family application such as+--+-- > ty :: TYPE (F x)+--+-- this function will emit a new Wanted 'Concrete#' constraint.+hasFixedRuntimeRep :: FRROrigin -> Type -> TcM ConcreteEvidence+hasFixedRuntimeRep frrOrig ty++ -- Shortcut: check for 'Type' and 'UnliftedType' type synonyms.+ | TyConApp tc [] <- ki+ , tc == liftedTypeKindTyCon || tc == unliftedTypeKindTyCon+ = return ConcreteReflEvidence++ | otherwise+ = do { th_stage <- getStage+ ; if+ -- We have evidence for 'Concrete# ty' right now:+ -- no need to emit a constraint/create an evidence hole.+ | isConcrete ki+ -> return ConcreteReflEvidence++ -- See [Wrinkle: Typed Template Haskell] in Note [hasFixedRuntimeRep].+ | Brack _ (TcPending {}) <- th_stage+ -> return ConcreteTypedTHNoEvidence++ -- Create a new Wanted 'Concrete#' constraint and emit it.+ | otherwise+ -> do { loc <- getCtLocM (FixedRuntimeRepOrigin ty frrOrig) (Just KindLevel)+ ; (hole, ct_ev) <- newConcretePrimWanted loc ki+ ; emitSimple $ mkNonCanonical ct_ev+ ; return $ ConcreteHoleEvidence hole } }+ where+ ki :: Kind+ ki = typeKind ty++-- | Create a new (initially unfilled) coercion hole,+-- to hold evidence for a @'Concrete#' (ty :: ki)@ constraint.+newConcreteHole :: Kind -- ^ Kind of the thing we want to ensure is concrete (e.g. 'runtimeRepTy')+ -> Type -- ^ Thing we want to ensure is concrete (e.g. some 'RuntimeRep')+ -> TcM ConcreteHole+newConcreteHole ki ty+ = do { concrete_ty <- newFlexiTyVarTy ki+ ; let co_ty = mkHeteroPrimEqPred ki ki ty concrete_ty+ ; newCoercionHole co_ty }++-- | Create a new 'Concrete#' constraint.+newConcretePrimWanted :: CtLoc -> Type -> TcM (ConcreteHole, CtEvidence)+newConcretePrimWanted loc ty+ = do { let+ ki :: Kind+ ki = typeKind ty+ ; hole <- newConcreteHole ki ty+ ; let+ wantedCtEv :: CtEvidence+ wantedCtEv =+ CtWanted+ { ctev_dest = HoleDest hole+ , ctev_pred = mkTyConApp concretePrimTyCon [ki, ty]+ , ctev_nosh = WOnly -- WOnly, because Derived Concrete# constraints+ -- aren't useful: solving a Concrete# constraint+ -- can't cause any unification to take place.+ , ctev_loc = loc+ }+ ; return (hole, wantedCtEv) }++{-***********************************************************************+* *+ HsWrapper+* *+***********************************************************************-}++-- | Smart constructor to create a 'WpFun' 'HsWrapper'.+--+-- Might emit a 'Concrete#' constraint, to check for+-- representation polymorphism. This is necessary, as 'WpFun' will desugar to+-- a lambda abstraction, whose binder must have a fixed runtime representation.+mkWpFun :: HsWrapper -> HsWrapper+ -> Scaled TcType -- ^ the "from" type of the first wrapper+ -> TcType -- ^ either type of the second wrapper (used only when the+ -- second wrapper is the identity)+ -> WpFunOrigin -- ^ what caused you to want a WpFun?+ -> TcM HsWrapper+mkWpFun WpHole WpHole _ _ _ = return $ WpHole+mkWpFun WpHole (WpCast co2) (Scaled w t1) _ _ = return $ WpCast (mkTcFunCo Representational (multToCo w) (mkTcRepReflCo t1) co2)+mkWpFun (WpCast co1) WpHole (Scaled w _) t2 _ = return $ WpCast (mkTcFunCo Representational (multToCo w) (mkTcSymCo co1) (mkTcRepReflCo t2))+mkWpFun (WpCast co1) (WpCast co2) (Scaled w _) _ _ = return $ WpCast (mkTcFunCo Representational (multToCo w) (mkTcSymCo co1) co2)+mkWpFun co1 co2 t1 _ wpFunOrig+ = do { _concrete_ev <- hasFixedRuntimeRep (FRRWpFun wpFunOrig) (scaledThing t1)+ ; return $ WpFun co1 co2 t1 }
compiler/GHC/Tc/Utils/Instantiate.hs view
@@ -69,12 +69,13 @@ import GHC.Tc.Utils.Env import GHC.Tc.Types.Evidence import GHC.Tc.Instance.FunDeps+import GHC.Tc.Utils.Concrete import GHC.Tc.Utils.TcMType import GHC.Tc.Utils.TcType import GHC.Tc.Errors.Types import GHC.Types.Id.Make( mkDictFunId )-import GHC.Types.Basic ( TypeOrKind(..) )+import GHC.Types.Basic ( TypeOrKind(..), Arity ) import GHC.Types.Error import GHC.Types.SourceText import GHC.Types.SrcLoc as SrcLoc@@ -95,7 +96,7 @@ import Data.List ( mapAccumL ) import qualified Data.List.NonEmpty as NE-import Control.Monad( unless )+import Control.Monad( when, unless, void ) import Data.Function ( on ) {-@@ -740,10 +741,10 @@ -} tcSyntaxName :: CtOrigin- -> TcType -- ^ Type to instantiate it at- -> (Name, HsExpr GhcRn) -- ^ (Standard name, user name)+ -> TcType -- ^ Type to instantiate it at+ -> (Name, HsExpr GhcRn) -- ^ (Standard name, user name) -> TcM (Name, HsExpr GhcTc)- -- ^ (Standard name, suitable expression)+ -- ^ (Standard name, suitable expression) -- USED ONLY FOR CmdTop (sigh) *** -- See Note [CmdSyntaxTable] in "GHC.Hs.Expr" @@ -755,35 +756,69 @@ tcSyntaxName orig ty (std_nm, user_nm_expr) = do std_id <- tcLookupId std_nm let- -- C.f. newMethodAtLoc ([tv], _, tau) = tcSplitSigmaTy (idType std_id) sigma1 = substTyWith [tv] [ty] tau -- Actually, the "tau-type" might be a sigma-type in the -- case of locally-polymorphic methods. - addErrCtxtM (syntaxNameCtxt user_nm_expr orig sigma1) $ do+ span <- getSrcSpanM+ addErrCtxtM (syntaxNameCtxt user_nm_expr orig sigma1 span) $ do -- Check that the user-supplied thing has the -- same type as the standard one. -- Tiresome jiggling because tcCheckSigma takes a located expression- span <- getSrcSpanM expr <- tcCheckPolyExpr (L (noAnnSrcSpan span) user_nm_expr) sigma1+ hasFixedRuntimeRepRes std_nm user_nm_expr sigma1 return (std_nm, unLoc expr) -syntaxNameCtxt :: HsExpr GhcRn -> CtOrigin -> Type -> TidyEnv+syntaxNameCtxt :: HsExpr GhcRn -> CtOrigin -> Type -> SrcSpan -> TidyEnv -> TcRn (TidyEnv, SDoc)-syntaxNameCtxt name orig ty tidy_env- = do { inst_loc <- getCtLocM orig (Just TypeLevel)- ; let msg = vcat [ text "When checking that" <+> quotes (ppr name)+syntaxNameCtxt name orig ty loc tidy_env = return (tidy_env, msg)+ where+ msg = vcat [ text "When checking that" <+> quotes (ppr name) <+> text "(needed by a syntactic construct)"- , nest 2 (text "has the required type:"- <+> ppr (tidyType tidy_env ty))- , nest 2 (pprCtLoc inst_loc) ]- ; return (tidy_env, msg) }+ , nest 2 (text "has the required type:"+ <+> ppr (tidyType tidy_env ty))+ , nest 2 (sep [ppr orig, text "at" <+> ppr loc])] {- ************************************************************************ * *+ FixedRuntimeRep+* *+************************************************************************+-}++-- | Check that the result type of an expression has a fixed runtime representation.+--+-- Used only for arrow operations such as 'arr', 'first', etc.+hasFixedRuntimeRepRes :: Name -> HsExpr GhcRn -> TcSigmaType -> TcM ()+hasFixedRuntimeRepRes std_nm user_expr ty = mapM_ do_check mb_arity+ where+ do_check :: Arity -> TcM ()+ do_check arity =+ let res_ty = nTimes arity (snd . splitPiTy) ty+ in void $ hasFixedRuntimeRep (FRRArrow $ ArrowFun user_expr) res_ty+ mb_arity :: Maybe Arity+ mb_arity -- arity of the arrow operation, counting type-level arguments+ | std_nm == arrAName -- result used as an argument in, e.g., do_premap+ = Just 3+ | std_nm == composeAName -- result used as an argument in, e.g., dsCmdStmt/BodyStmt+ = Just 5+ | std_nm == firstAName -- result used as an argument in, e.g., dsCmdStmt/BodyStmt+ = Just 4+ | std_nm == appAName -- result used as an argument in, e.g., dsCmd/HsCmdArrApp/HsHigherOrderApp+ = Just 2+ | std_nm == choiceAName -- result used as an argument in, e.g., HsCmdIf+ = Just 5+ | std_nm == loopAName -- result used as an argument in, e.g., HsCmdIf+ = Just 4+ | otherwise+ = Nothing++{-+************************************************************************+* * Instances * * ************************************************************************@@ -827,7 +862,8 @@ ; oflag <- getOverlapFlag overlap_mode ; let inst = mkLocalInstance dfun oflag tvs' clas tys'- ; warnIf (isOrphan (is_orphan inst)) (TcRnOrphanInstance inst)+ ; when (isOrphan (is_orphan inst)) $+ addDiagnostic (TcRnOrphanInstance inst) ; return inst } tcExtendLocalInstEnv :: [ClsInst] -> TcM a -> TcM a
compiler/GHC/Tc/Utils/Monad.hs view
@@ -351,6 +351,7 @@ tcg_dependent_files = dependent_files_var, tcg_tc_plugin_solvers = [], tcg_tc_plugin_rewriters = emptyUFM,+ tcg_defaulting_plugins = [], tcg_hf_plugins = [], tcg_top_loc = loc, tcg_static_wc = static_wc_var,@@ -2086,7 +2087,7 @@ if_doc = text "initIfaceLoad", if_rec_types = emptyKnotVars }- initTcRnIf 'i' hsc_env gbl_env () do_this+ initTcRnIf 'i' (hsc_env { hsc_type_env_vars = emptyKnotVars }) gbl_env () do_this -- | This is used when we are doing to call 'typecheckModule' on an 'ModIface', -- if it's part of a loop with some other modules then we need to use their
compiler/GHC/Tc/Utils/TcMType.hs view
@@ -66,7 +66,7 @@ -------------------------------- -- Zonking and tidying- zonkTidyTcType, zonkTidyTcTypes, zonkTidyOrigin,+ zonkTidyTcType, zonkTidyTcTypes, zonkTidyOrigin, zonkTidyOrigins, tidyEvVar, tidyCt, tidyHole, tidySkolemInfo, zonkTcTyVar, zonkTcTyVars, zonkTcTyVarToTyVar, zonkInvisTVBinder,@@ -93,7 +93,7 @@ ------------------------------ -- Representation polymorphism- ensureNotLevPoly, checkForLevPoly, checkForLevPolyX,+ checkTypeHasFixedRuntimeRep, ) where import GHC.Prelude@@ -116,6 +116,7 @@ import GHC.Core.Coercion import GHC.Core.Class import GHC.Core.Predicate+import GHC.Core.InstEnv (ClsInst(is_tys)) import GHC.Types.Var import GHC.Types.Id as Id@@ -127,7 +128,8 @@ import GHC.Types.Var.Env import GHC.Types.Name.Env import GHC.Types.Unique.Set-import GHC.Types.Basic ( TypeOrKind(..) )+import GHC.Types.Basic ( TypeOrKind(..)+ , DefaultKindVars(..), DefaultVarsOfKind(..), allVarsOfKindDefault ) import GHC.Data.FastString import GHC.Data.Bag@@ -203,7 +205,7 @@ cloneWanted :: Ct -> TcM Ct cloneWanted ct- | ev@(CtWanted { ctev_pred = pty }) <- ctEvidence ct+ | ev@(CtWanted { ctev_pred = pty, ctev_dest = HoleDest _ }) <- ctEvidence ct = do { co_hole <- newCoercionHole pty ; return (mkNonCanonical (ev { ctev_dest = HoleDest co_hole })) } | otherwise@@ -307,6 +309,9 @@ EqPred {} -> mkVarOccFS (fsLit "co") IrredPred {} -> mkVarOccFS (fsLit "irred") ForAllPred {} -> mkVarOccFS (fsLit "df")+ SpecialPred special_pred _ ->+ case special_pred of+ ConcretePrimPred -> mkVarOccFS (fsLit "concr") -- | Create a new 'Implication' with as many sensible defaults for its fields -- as possible. Note that the 'ic_tclvl', 'ic_binds', and 'ic_info' fields do@@ -987,10 +992,10 @@ 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 = tcIsConstraintKind zonked_tv_kind- || tcEqKind zonked_ty_kind zonked_tv_kind- -- Hack alert! tcIsConstraintKind: see GHC.Tc.Gen.HsType- -- Note [Extra-constraint holes in partial type signatures]+ 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") 2 ( ppr tyvar <+> text "::" <+> (ppr tv_kind $$ ppr zonked_tv_kind)@@ -1686,7 +1691,8 @@ Note [Deterministic UniqFM] in GHC.Types.Unique.DFM. -} -quantifyTyVars :: CandidatesQTvs -- See Note [Dependent type variables]+quantifyTyVars :: DefaultVarsOfKind+ -> CandidatesQTvs -- See Note [Dependent type variables] -- Already zonked -> TcM [TcTyVar] -- See Note [quantifyTyVars]@@ -1696,16 +1702,18 @@ -- invariants on CandidateQTvs, we do not have to filter out variables -- free in the environment here. Just quantify unconditionally, subject -- to the restrictions in Note [quantifyTyVars].-quantifyTyVars dvs+quantifyTyVars def_varsOfKind dvs -- short-circuit common case | isEmptyCandidates dvs = do { traceTc "quantifyTyVars has nothing to quantify" empty ; return [] } | otherwise- = do { traceTc "quantifyTyVars {" (ppr dvs)+ = do { traceTc "quantifyTyVars {"+ ( vcat [ text "def_varsOfKind =" <+> ppr def_varsOfKind+ , text "dvs =" <+> ppr dvs ]) - ; undefaulted <- defaultTyVars dvs+ ; undefaulted <- defaultTyVars def_varsOfKind dvs ; final_qtvs <- mapMaybeM zonk_quant undefaulted ; traceTc "quantifyTyVars }"@@ -1783,11 +1791,12 @@ _other -> pprPanic "skolemiseQuantifiedTyVar" (ppr tv) -- RuntimeUnk -defaultTyVar :: Bool -- True <=> please default this kind variable to *+defaultTyVar :: DefaultKindVars+ -> DefaultVarsOfKind -> TcTyVar -- If it's a MetaTyVar then it is unbound -> TcM Bool -- True <=> defaulted away altogether -defaultTyVar default_kind tv+defaultTyVar def_kindVars def_varsOfKind tv | not (isMetaTyVar tv) = return False @@ -1799,22 +1808,26 @@ = return False - | isRuntimeRepVar tv -- Do not quantify over a RuntimeRep var- -- unless it is a TyVarTv, handled earlier+ | isRuntimeRepVar tv+ , def_runtimeRep def_varsOfKind+ -- Do not quantify over a RuntimeRep var+ -- unless it is a TyVarTv, handled earlier = do { traceTc "Defaulting a RuntimeRep var to LiftedRep" (ppr tv) ; writeMetaTyVar tv liftedRepTy ; return True } | isLevityVar tv+ , def_levity def_varsOfKind = do { traceTc "Defaulting a Levity var to Lifted" (ppr tv) ; writeMetaTyVar tv liftedDataConTy ; return True } | isMultiplicityVar tv+ , def_multiplicity def_varsOfKind = do { traceTc "Defaulting a Multiplicty var to Many" (ppr tv) ; writeMetaTyVar tv manyDataConTy ; return True } - | default_kind -- -XNoPolyKinds and this is a kind var- = default_kind_var tv -- so default it to * if possible+ | DefaultKinds <- def_kindVars -- -XNoPolyKinds and this is a kind var+ = default_kind_var tv -- so default it to * if possible | otherwise = return False@@ -1851,12 +1864,15 @@ -- Multiplicity tyvars default to Many -- Type tyvars from dv_kvs default to Type, when -XNoPolyKinds -- (under -XNoPolyKinds, non-defaulting vars in dv_kvs is an error)-defaultTyVars :: CandidatesQTvs -- ^ all candidates for quantification+defaultTyVars :: DefaultVarsOfKind+ -> CandidatesQTvs -- ^ all candidates for quantification -> TcM [TcTyVar] -- ^ those variables not defaulted-defaultTyVars dvs+defaultTyVars def_varsOfKind dvs = do { poly_kinds <- xoptM LangExt.PolyKinds- ; defaulted_kvs <- mapM (defaultTyVar (not poly_kinds)) dep_kvs- ; defaulted_tvs <- mapM (defaultTyVar False) nondep_tvs+ ; let+ def_kinds = if poly_kinds then Don'tDefaultKinds else DefaultKinds+ ; defaulted_kvs <- mapM (defaultTyVar def_kinds def_varsOfKind ) dep_kvs+ ; defaulted_tvs <- mapM (defaultTyVar Don'tDefaultKinds def_varsOfKind ) nondep_tvs ; let undefaulted_kvs = [ kv | (kv, False) <- dep_kvs `zip` defaulted_kvs ] undefaulted_tvs = [ tv | (tv, False) <- nondep_tvs `zip` defaulted_tvs ] ; return (undefaulted_kvs ++ undefaulted_tvs) }@@ -2013,7 +2029,7 @@ | otherwise = do { traceTc "doNotQuantifyTyVars" (ppr dvs)- ; undefaulted <- defaultTyVars dvs+ ; undefaulted <- defaultTyVars allVarsOfKindDefault dvs -- could have regular TyVars here, in an associated type RHS, or -- bound by a type declaration head. So filter looking only for -- metavars. e.g. b and c in `class (forall a. a b ~ a c) => C b c`@@ -2550,8 +2566,20 @@ ; (env2, p2') <- zonkTidyTcType env1 p2 ; (env3, o1') <- zonkTidyOrigin env2 o1 ; return (env3, FunDepOrigin2 p1' o1' p2' l2) }+zonkTidyOrigin env (CycleBreakerOrigin orig)+ = do { (env1, orig') <- zonkTidyOrigin env orig+ ; return (env1, CycleBreakerOrigin orig') }+zonkTidyOrigin env (InstProvidedOrigin mod cls_inst)+ = do { (env1, is_tys') <- mapAccumLM zonkTidyTcType env (is_tys cls_inst)+ ; return (env1, InstProvidedOrigin mod (cls_inst {is_tys = is_tys'})) }+zonkTidyOrigin env (FixedRuntimeRepOrigin ty frr_orig)+ = do { (env1, ty') <- zonkTidyTcType env ty+ ; return (env1, FixedRuntimeRepOrigin ty' frr_orig)} zonkTidyOrigin env orig = return (env, orig) +zonkTidyOrigins :: TidyEnv -> [CtOrigin] -> TcM (TidyEnv, [CtOrigin])+zonkTidyOrigins = mapAccumLM zonkTidyOrigin+ ---------------- tidyCt :: TidyEnv -> Ct -> Ct -- Used only in error reporting@@ -2614,43 +2642,22 @@ %* * Representation polymorphism checks * *-*************************************************************************--See Note [Representation polymorphism checking] in GHC.HsToCore.Monad---}---- | According to the rules around representation polymorphism--- (see https://gitlab.haskell.org/ghc/ghc/wikis/no-sub-kinds), no binder--- can have a representation-polymorphic type. This check ensures--- that we respect this rule. It is a bit regrettable that this error--- occurs in zonking, after which we should have reported all errors.--- But it's hard to see where else to do it, because this can be discovered--- only after all solving is done. And, perhaps most importantly, this--- isn't really a compositional property of a type system, so it's--- not a terrible surprise that the check has to go in an awkward spot.-ensureNotLevPoly :: Type -- its zonked type- -> LevityCheckProvenance -- where this happened- -> TcM ()-ensureNotLevPoly ty provenance- = whenNoErrs $ -- sometimes we end up zonking bogus definitions of type- -- forall a. a. See, for example, test ghci/scripts/T9140- checkForLevPoly provenance ty-- -- See Note [Representation polymorphism checking] in GHC.HsToCore.Monad-checkForLevPoly :: LevityCheckProvenance -> Type -> TcM ()-checkForLevPoly = checkForLevPolyX (\ty -> addDetailedDiagnostic . TcLevityPolyInType ty)+***********************************************************************-} -checkForLevPolyX :: Monad m- => (Type -> LevityCheckProvenance -> m ()) -- how to report an error- -> LevityCheckProvenance- -> Type- -> m ()-checkForLevPolyX add_err provenance ty- | isTypeLevPoly ty- = add_err ty provenance- | otherwise- = return ()+-- | Check that the specified type has a fixed runtime representation.+--+-- If it isn't, throw a representation-polymorphism error appropriate+-- for the context (as specified by the 'FixedRuntimeRepProvenance').+--+-- Unlike the other representation polymorphism checks, which emit+-- 'Concrete#' constraints, this function does not emit any constraints,+-- as it has enough information to immediately make a decision.+--+-- See (1) in Note [Representation polymorphism checking] in GHC.Tc.Utils.Concrete+checkTypeHasFixedRuntimeRep :: FixedRuntimeRepProvenance -> Type -> TcM ()+checkTypeHasFixedRuntimeRep prov ty =+ unless (typeHasFixedRuntimeRep ty)+ (addDetailedDiagnostic $ TcRnTypeDoesNotHaveFixedRuntimeRep ty prov) {- %************************************************************************
compiler/GHC/Tc/Utils/Unify.hs view
@@ -43,18 +43,23 @@ import GHC.Hs import GHC.Core.TyCo.Rep import GHC.Core.TyCo.Ppr( debugPprType )-import GHC.Tc.Utils.TcMType+import GHC.Tc.Utils.Concrete ( mkWpFun )+import GHC.Tc.Utils.Env+import GHC.Tc.Utils.Instantiate import GHC.Tc.Utils.Monad+import GHC.Tc.Utils.TcMType import GHC.Tc.Utils.TcType-import GHC.Tc.Utils.Env++ import GHC.Core.Type import GHC.Core.Coercion import GHC.Core.Multiplicity+ import GHC.Tc.Types.Evidence import GHC.Tc.Types.Constraint import GHC.Tc.Types.Origin import GHC.Types.Name( isSystemName )-import GHC.Tc.Utils.Instantiate+ import GHC.Core.TyCon import GHC.Builtin.Types import GHC.Types.Var as Var@@ -210,13 +215,9 @@ (n_val_args_wanted, so_far) fun_ty ; (wrap_res, arg_tys, res_ty) <- go (n-1) (arg_ty1:so_far) res_ty1- ; let wrap_fun2 = mkWpFun idHsWrapper wrap_res arg_ty1 res_ty doc+ ; wrap_fun2 <- mkWpFun idHsWrapper wrap_res arg_ty1 res_ty (WpFunFunTy fun_ty) ; return (wrap_fun2 <.> wrap_fun1, arg_ty1:arg_tys, res_ty) }- where- doc = text "When inferring the argument type of a function with type" <+>- quotes (ppr fun_ty) - {- ************************************************************************ * *@@ -320,11 +321,8 @@ = assert (af == VisArg) $ do { (wrap_res, result) <- go ((Scaled mult $ mkCheckExpType arg_ty) : acc_arg_tys) (n-1) res_ty- ; let fun_wrap = mkWpFun idHsWrapper wrap_res (Scaled mult arg_ty) res_ty doc+ ; fun_wrap <- mkWpFun idHsWrapper wrap_res (Scaled mult arg_ty) res_ty (WpFunFunExpTy orig_ty) ; return ( fun_wrap, result ) }- where- doc = text "When inferring the argument type of a function with type" <+>- quotes (ppr orig_ty) go acc_arg_tys n ty@(TyVarTy tv) | isMetaTyVar tv@@ -779,7 +777,7 @@ returned by tcSubMult (and derived functions such as tcCheckUsage and checkManyPattern) is quite unlike any other wrapper: it checks whether the coercion produced by the constraint solver is trivial, producing a type error-is it is not. This is implemented via the WpMultCoercion wrapper, as desugared+if it is not. This is implemented via the WpMultCoercion wrapper, as desugared by GHC.HsToCore.Binds.dsHsWrapper, which does the reflexivity check. This wrapper needs to be placed in the term; otherwise, checking of the@@ -788,11 +786,14 @@ Why do we check this in the desugarer? It's a convenient place, since it's right after all the constraints are solved. We need the constraints to be-solved to check whether they are trivial or not. Plus there is precedent for-type errors during desuraging (such as the representation polymorphism-restriction). An alternative would be to have a kind of constraint which can-only produce trivial evidence, then this check would happen in the constraint-solver (#18756).+solved to check whether they are trivial or not.++An alternative would be to have a kind of constraint which can+only produce trivial evidence. This would allow such checks to happen+in the constraint solver (#18756).+This would be similar to the existing setup for Concrete, see+ Note [The Concrete mechanism] in GHC.Tc.Utils.Concrete+ (PHASE 1 in particular). -} tcSubMult :: CtOrigin -> Mult -> Mult -> TcM HsWrapper@@ -1763,38 +1764,6 @@ Revisited in Nov '20, along with removing flattening variables. Problem is still present, and the solution is still the same.--Note [Refactoring hazard: metaTyVarUpdateOK]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-I (Richard E.) have a sad story about refactoring this code, retained here-to prevent others (or a future me!) from falling into the same traps.--It all started with #11407, which was caused by the fact that the TyVarTy-case of defer_me didn't look in the kind. But it seemed reasonable to-simply remove the defer_me check instead.--It referred to two Notes (since removed) that were out of date, and the-fast_check code in occurCheckExpand seemed to do just about the same thing as-defer_me. The one piece that defer_me did that wasn't repeated by-occurCheckExpand was the type-family check. (See Note [Prevent unification-with type families].) So I checked the result of occurCheckExpand for any-type family occurrences and deferred if there were any. This was done-in commit e9bf7bb5cc9fb3f87dd05111aa23da76b86a8967 .--This approach turned out not to be performant, because the expanded-type was bigger than the original type, and tyConsOfType (needed to-see if there are any type family occurrences) looks through type-synonyms. So it then struck me that we could dispense with the-defer_me check entirely. This simplified the code nicely, and it cut-the allocations in T5030 by half. But, as documented in Note [Prevent-unification with type families], this destroyed performance in-T3064. Regardless, I missed this regression and the change was-committed as 3f5d1a13f112f34d992f6b74656d64d95a3f506d .--Bottom lines:- * defer_me is back, but now fixed w.r.t. #11407.- * Tread carefully before you start to refactor here. There can be- lots of hard-to-predict consequences. Note [Type synonyms and the occur check] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compiler/GHC/Tc/Utils/Zonk.hs view
@@ -49,7 +49,6 @@ import GHC.Hs -import GHC.Tc.Errors.Types ( LevityCheckProvenance(..) ) import {-# SOURCE #-} GHC.Tc.Gen.Splice (runTopSplice) import GHC.Tc.Utils.Monad import GHC.Tc.TyCl.Build ( TcMethInfo, MethInfo )@@ -387,8 +386,6 @@ zonkIdBndr :: ZonkEnv -> TcId -> TcM Id zonkIdBndr env v = do Scaled w' ty' <- zonkScaledTcTypeToTypeX env (idScaledType v)- ensureNotLevPoly ty' (LevityCheckInBinder v)- return (modifyIdInfo (`setLevityInfoWithType` ty') (setIdMult (setIdType v ty') w')) zonkIdBndrs :: ZonkEnv -> [TcId] -> TcM [Id]@@ -1065,10 +1062,10 @@ zonkCoFn env (WpCompose c1 c2) = do { (env1, c1') <- zonkCoFn env c1 ; (env2, c2') <- zonkCoFn env1 c2 ; return (env2, WpCompose c1' c2') }-zonkCoFn env (WpFun c1 c2 t1 d) = do { (env1, c1') <- zonkCoFn env c1- ; (env2, c2') <- zonkCoFn env1 c2- ; t1' <- zonkScaledTcTypeToTypeX env2 t1- ; return (env2, WpFun c1' c2' t1' d) }+zonkCoFn env (WpFun c1 c2 t1) = do { (env1, c1') <- zonkCoFn env c1+ ; (env2, c2') <- zonkCoFn env1 c2+ ; t1' <- zonkScaledTcTypeToTypeX env2 t1+ ; return (env2, WpFun c1' c2' t1') } zonkCoFn env (WpCast co) = do { co' <- zonkCoToCo env co ; return (env, WpCast co') } zonkCoFn env (WpEvLam ev) = do { (env', ev') <- zonkEvBndrX env ev@@ -1348,7 +1345,6 @@ zonk_pat env (WildPat ty) = do { ty' <- zonkTcTypeToTypeX env ty- ; ensureNotLevPoly ty' LevityCheckInWildcardPattern ; return (env, WildPat ty') } zonk_pat env (VarPat x (L l v))@@ -1389,8 +1385,7 @@ ; (env', pat') <- zonkPat env pat ; return (env', SumPat tys' pat' alt arity) } -zonk_pat env p@(ConPat { pat_con = L _ con- , pat_args = args+zonk_pat env p@(ConPat { pat_args = args , pat_con_ext = p'@(ConPatTc { cpt_tvs = tyvars , cpt_dicts = evs@@ -1401,16 +1396,6 @@ }) = assert (all isImmutableTyVar tyvars) $ do { new_tys <- mapM (zonkTcTypeToTypeX env) tys-- -- an unboxed tuple pattern (but only an unboxed tuple pattern)- -- might have representation-polymorphic arguments.- -- Check for this badness.- ; case con of- RealDataCon dc- | isUnboxedTupleTyCon (dataConTyCon dc)- -> mapM_ (checkForLevPoly (LevityCheckInUnboxedTuplePattern p)) (dropRuntimeRepArgs new_tys)- _ -> return ()- ; (env0, new_tyvars) <- zonkTyBndrsX env tyvars -- Must zonk the existential variables, because their -- /kind/ need potential zonking.
compiler/GHC/Tc/Validity.hs view
@@ -1,4 +1,5 @@ +{-# LANGUAGE DerivingStrategies #-} {-# OPTIONS_GHC -Wno-incomplete-record-updates #-} {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}@@ -32,7 +33,7 @@ import GHC.Core.TyCo.Rep import GHC.Core.TyCo.Ppr import GHC.Tc.Utils.TcType hiding ( sizeType, sizeTypes )-import GHC.Builtin.Types ( heqTyConName, eqTyConName, coercibleTyConName, manyDataConTy )+import GHC.Builtin.Types import GHC.Builtin.Names import GHC.Core.Type import GHC.Core.Unify ( tcMatchTyX_BM, BindFlag(..) )@@ -692,8 +693,10 @@ check_type ve ty@(TyConApp tc tys) | isTypeSynonymTyCon tc || isTypeFamilyTyCon tc = check_syn_tc_app ve ty tc tys- | isUnboxedTupleTyCon tc = check_ubx_tuple ve ty tys- | otherwise = mapM_ (check_arg_type False ve) tys+ | isUnboxedTupleTyCon tc+ = check_ubx_tuple ve ty tys+ | otherwise+ = mapM_ (check_arg_type False ve) tys check_type _ (LitTy {}) = return () @@ -1384,11 +1387,12 @@ Note [Instances of built-in classes in signature files] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -User defined instances for KnownNat, KnownSymbol and Typeable are-disallowed -- they are generated when needed by GHC itself on-the-fly.+User defined instances for KnownNat, KnownSymbol, KnownChar,+and Typeable are disallowed+ -- they are generated when needed by GHC itself, on-the-fly. However, if they occur in a Backpack signature file, they have an-entirely different meaning. Suppose in M.hsig we see+entirely different meaning. To illustrate, suppose in M.hsig we see signature M where data T :: Nat@@ -1407,6 +1411,7 @@ check_special_inst_head :: DynFlags -> Bool -> Bool -> UserTypeCtxt -> Class -> [Type] -> TcM () -- Wow! There are a surprising number of ad-hoc special cases here.+-- TODO: common up the logic for special typeclasses (see GHC ticket #20441). check_special_inst_head dflags is_boot is_sig ctxt clas cls_args -- If not in an hs-boot file, abstract classes cannot have instances@@ -1421,15 +1426,15 @@ , not is_sig -- Note [Instances of built-in classes in signature files] , hand_written_bindings- = failWithTc rejected_class_msg+ = failWithTc $ TcRnSpecialClassInst clas False - -- Handwritten instances of KnownNat/KnownSymbol class- -- are always forbidden (#12837)+ -- Handwritten instances of KnownNat/KnownSymbol+ -- are forbidden outside of signature files (#12837) | clas_nm `elem` [ knownNatClassName, knownSymbolClassName ] , not is_sig -- Note [Instances of built-in classes in signature files] , hand_written_bindings- = failWithTc rejected_class_msg+ = failWithTc $ TcRnSpecialClassInst clas False -- For the most part we don't allow -- instances for (~), (~~), or Coercible;@@ -1437,12 +1442,12 @@ -- f :: (forall a b. Coercible a b => Coercible (m a) (m b)) => ...m... | clas_nm `elem` [ heqTyConName, eqTyConName, coercibleTyConName ] , not quantified_constraint- = failWithTc rejected_class_msg+ = failWithTc $ TcRnSpecialClassInst clas False -- Check for hand-written Generic instances (disallowed in Safe Haskell) | clas_nm `elem` genericClassNames , hand_written_bindings- = do { failIfTc (safeLanguageOn dflags) gen_inst_err+ = do { failIfTc (safeLanguageOn dflags) (TcRnSpecialClassInst clas True) ; when (safeInferOn dflags) (recordUnsafeInfer emptyMessages) } | clas_nm == hasFieldClassName@@ -1501,18 +1506,6 @@ text "Only one type can be given in an instance head." $$ text "Use MultiParamTypeClasses if you want to allow more, or zero." - rejected_class_msg :: TcRnMessage- rejected_class_msg = TcRnUnknownMessage $ mkPlainError noHints $ rejected_class_doc-- rejected_class_doc :: SDoc- rejected_class_doc =- text "Class" <+> quotes (ppr clas_nm)- <+> text "does not support user-specified instances"-- gen_inst_err :: TcRnMessage- gen_inst_err = TcRnUnknownMessage $ mkPlainError noHints $- rejected_class_doc $$ nest 2 (text "(in Safe Haskell)")- mb_ty_args_msg | not (xopt LangExt.TypeSynonymInstances dflags) , not (all tcInstHeadTyNotSynonym ty_args)@@ -1819,8 +1812,9 @@ check :: VarSet -> PredType -> TcM () check foralld_tvs pred = case classifyPredType pred of- EqPred {} -> return () -- See #4200.- IrredPred {} -> check2 foralld_tvs pred (sizeType pred)+ EqPred {} -> return () -- See #4200.+ SpecialPred {} -> return ()+ IrredPred {} -> check2 foralld_tvs pred (sizeType pred) ClassPred cls tys | isTerminatingClass cls -> return ()@@ -2834,6 +2828,7 @@ -- The filtering looks bogus -- See Note [Invisible arguments and termination] go (EqPred {}) = 0+ go (SpecialPred {}) = 0 go (IrredPred ty) = sizeType ty go (ForAllPred _ _ pred) = goClass pred
+ compiler/GHC/Unit/Finder.hs view
@@ -0,0 +1,665 @@+{-+(c) The University of Glasgow, 2000-2006++-}+++{-# LANGUAGE FlexibleContexts #-}++-- | Module finder+module GHC.Unit.Finder (+ FindResult(..),+ InstalledFindResult(..),+ FinderOpts(..),+ FinderCache,+ initFinderCache,+ flushFinderCaches,+ findImportedModule,+ findPluginModule,+ findExactModule,+ findHomeModule,+ findExposedPackageModule,+ mkHomeModLocation,+ mkHomeModLocation2,+ mkHiOnlyModLocation,+ mkHiPath,+ mkObjPath,+ addHomeModuleToFinder,+ uncacheModule,+ mkStubPaths,++ findObjectLinkableMaybe,+ findObjectLinkable,++ -- Hash cache+ lookupFileCache+ ) where++import GHC.Prelude++import GHC.Platform.Ways++import GHC.Builtin.Names ( gHC_PRIM )++import GHC.Unit.Types+import GHC.Unit.Module+import GHC.Unit.Home+import GHC.Unit.State+import GHC.Unit.Finder.Types++import GHC.Data.Maybe ( expectJust )+import qualified GHC.Data.ShortText as ST++import GHC.Utils.Misc+import GHC.Utils.Outputable as Outputable+import GHC.Utils.Panic++import GHC.Linker.Types+import GHC.Types.PkgQual++import GHC.Fingerprint+import Data.IORef+import System.Directory+import System.FilePath+import Control.Monad+import Data.Time+import qualified Data.Map as M+++type FileExt = String -- Filename extension+type BaseName = String -- Basename of file++-- -----------------------------------------------------------------------------+-- The Finder++-- The Finder provides a thin filesystem abstraction to the rest of+-- the compiler. For a given module, it can tell you where the+-- source, interface, and object files for that module live.++-- It does *not* know which particular package a module lives in. Use+-- Packages.lookupModuleInAllUnits for that.++-- -----------------------------------------------------------------------------+-- The finder's cache+++initFinderCache :: IO FinderCache+initFinderCache = FinderCache <$> newIORef emptyInstalledModuleEnv+ <*> newIORef M.empty++-- remove all the home modules from the cache; package modules are+-- assumed to not move around during a session; also flush the file hash+-- cache+flushFinderCaches :: FinderCache -> HomeUnit -> IO ()+flushFinderCaches (FinderCache ref file_ref) home_unit = do+ atomicModifyIORef' ref $ \fm -> (filterInstalledModuleEnv is_ext fm, ())+ atomicModifyIORef' file_ref $ \_ -> (M.empty, ())+ where+ is_ext mod _ = not (isHomeInstalledModule home_unit mod)++addToFinderCache :: FinderCache -> InstalledModule -> InstalledFindResult -> IO ()+addToFinderCache (FinderCache ref _) key val =+ atomicModifyIORef' ref $ \c -> (extendInstalledModuleEnv c key val, ())++removeFromFinderCache :: FinderCache -> InstalledModule -> IO ()+removeFromFinderCache (FinderCache ref _) key =+ atomicModifyIORef' ref $ \c -> (delInstalledModuleEnv c key, ())++lookupFinderCache :: FinderCache -> InstalledModule -> IO (Maybe InstalledFindResult)+lookupFinderCache (FinderCache ref _) key = do+ c <- readIORef ref+ return $! lookupInstalledModuleEnv c key++lookupFileCache :: FinderCache -> FilePath -> IO Fingerprint+lookupFileCache (FinderCache _ ref) key = do+ c <- readIORef ref+ case M.lookup key c of+ Nothing -> do+ hash <- getFileHash key+ atomicModifyIORef' ref $ \c -> (M.insert key hash c, ())+ return hash+ Just fp -> return fp++-- -----------------------------------------------------------------------------+-- The three external entry points+++-- | Locate a module that was imported by the user. We have the+-- module's name, and possibly a package name. Without a package+-- name, this function will use the search path and the known exposed+-- packages to find the module, if a package is specified then only+-- that package is searched for the module.++findImportedModule+ :: FinderCache+ -> FinderOpts+ -> UnitState+ -> HomeUnit+ -> ModuleName+ -> PkgQual+ -> IO FindResult+findImportedModule fc fopts units home_unit mod_name mb_pkg =+ case mb_pkg of+ NoPkgQual -> unqual_import+ ThisPkg _ -> home_import+ OtherPkg _ -> pkg_import+ where+ home_import = findHomeModule fc fopts home_unit mod_name+ pkg_import = findExposedPackageModule fc fopts units mod_name mb_pkg+ unqual_import = home_import+ `orIfNotFound`+ findExposedPackageModule fc fopts units mod_name NoPkgQual++-- | Locate a plugin module requested by the user, for a compiler+-- plugin. This consults the same set of exposed packages as+-- 'findImportedModule', unless @-hide-all-plugin-packages@ or+-- @-plugin-package@ are specified.+findPluginModule :: FinderCache -> FinderOpts -> UnitState -> HomeUnit -> ModuleName -> IO FindResult+findPluginModule fc fopts units home_unit mod_name =+ findHomeModule fc fopts home_unit mod_name+ `orIfNotFound`+ findExposedPluginPackageModule fc fopts units mod_name++-- | Locate a specific 'Module'. The purpose of this function is to+-- create a 'ModLocation' for a given 'Module', that is to find out+-- where the files associated with this module live. It is used when+-- reading the interface for a module mentioned by another interface,+-- for example (a "system import").++findExactModule :: FinderCache -> FinderOpts -> UnitState -> HomeUnit -> InstalledModule -> IO InstalledFindResult+findExactModule fc fopts unit_state home_unit mod = do+ if isHomeInstalledModule home_unit mod+ then findInstalledHomeModule fc fopts home_unit (moduleName mod)+ else findPackageModule fc unit_state fopts mod++-- -----------------------------------------------------------------------------+-- Helpers++-- | Given a monadic actions @this@ and @or_this@, first execute+-- @this@. If the returned 'FindResult' is successful, return+-- it; otherwise, execute @or_this@. If both failed, this function+-- also combines their failure messages in a reasonable way.+orIfNotFound :: Monad m => m FindResult -> m FindResult -> m FindResult+orIfNotFound this or_this = do+ res <- this+ case res of+ NotFound { fr_paths = paths1, fr_mods_hidden = mh1+ , fr_pkgs_hidden = ph1, fr_unusables = u1, fr_suggestions = s1 }+ -> do res2 <- or_this+ case res2 of+ NotFound { fr_paths = paths2, fr_pkg = mb_pkg2, fr_mods_hidden = mh2+ , fr_pkgs_hidden = ph2, fr_unusables = u2+ , fr_suggestions = s2 }+ -> return (NotFound { fr_paths = paths1 ++ paths2+ , fr_pkg = mb_pkg2 -- snd arg is the package search+ , fr_mods_hidden = mh1 ++ mh2+ , fr_pkgs_hidden = ph1 ++ ph2+ , fr_unusables = u1 ++ u2+ , fr_suggestions = s1 ++ s2 })+ _other -> return res2+ _other -> return res++-- | Helper function for 'findHomeModule': this function wraps an IO action+-- which would look up @mod_name@ in the file system (the home package),+-- and first consults the 'hsc_FC' cache to see if the lookup has already+-- been done. Otherwise, do the lookup (with the IO action) and save+-- the result in the finder cache and the module location cache (if it+-- was successful.)+homeSearchCache :: FinderCache -> HomeUnit -> ModuleName -> IO InstalledFindResult -> IO InstalledFindResult+homeSearchCache fc home_unit mod_name do_this = do+ let mod = mkHomeInstalledModule home_unit mod_name+ modLocationCache fc mod do_this++findExposedPackageModule :: FinderCache -> FinderOpts -> UnitState -> ModuleName -> PkgQual -> IO FindResult+findExposedPackageModule fc fopts units mod_name mb_pkg =+ findLookupResult fc fopts+ $ lookupModuleWithSuggestions units mod_name mb_pkg++findExposedPluginPackageModule :: FinderCache -> FinderOpts -> UnitState -> ModuleName -> IO FindResult+findExposedPluginPackageModule fc fopts units mod_name =+ findLookupResult fc fopts+ $ lookupPluginModuleWithSuggestions units mod_name NoPkgQual++findLookupResult :: FinderCache -> FinderOpts -> LookupResult -> IO FindResult+findLookupResult fc fopts r = case r of+ LookupFound m pkg_conf -> do+ let im = fst (getModuleInstantiation m)+ r' <- findPackageModule_ fc fopts im (fst pkg_conf)+ case r' of+ -- TODO: ghc -M is unlikely to do the right thing+ -- with just the location of the thing that was+ -- instantiated; you probably also need all of the+ -- implicit locations from the instances+ InstalledFound loc _ -> return (Found loc m)+ InstalledNoPackage _ -> return (NoPackage (moduleUnit m))+ InstalledNotFound fp _ -> return (NotFound{ fr_paths = fp, fr_pkg = Just (moduleUnit m)+ , fr_pkgs_hidden = []+ , fr_mods_hidden = []+ , fr_unusables = []+ , fr_suggestions = []})+ LookupMultiple rs ->+ return (FoundMultiple rs)+ LookupHidden pkg_hiddens mod_hiddens ->+ return (NotFound{ fr_paths = [], fr_pkg = Nothing+ , fr_pkgs_hidden = map (moduleUnit.fst) pkg_hiddens+ , fr_mods_hidden = map (moduleUnit.fst) mod_hiddens+ , fr_unusables = []+ , fr_suggestions = [] })+ LookupUnusable unusable ->+ let unusables' = map get_unusable unusable+ get_unusable (m, ModUnusable r) = (moduleUnit m, r)+ get_unusable (_, r) =+ pprPanic "findLookupResult: unexpected origin" (ppr r)+ in return (NotFound{ fr_paths = [], fr_pkg = Nothing+ , fr_pkgs_hidden = []+ , fr_mods_hidden = []+ , fr_unusables = unusables'+ , fr_suggestions = [] })+ LookupNotFound suggest -> do+ let suggest'+ | finder_enableSuggestions fopts = suggest+ | otherwise = []+ return (NotFound{ fr_paths = [], fr_pkg = Nothing+ , fr_pkgs_hidden = []+ , fr_mods_hidden = []+ , fr_unusables = []+ , fr_suggestions = suggest' })++modLocationCache :: FinderCache -> InstalledModule -> IO InstalledFindResult -> IO InstalledFindResult+modLocationCache fc mod do_this = do+ m <- lookupFinderCache fc mod+ case m of+ Just result -> return result+ Nothing -> do+ result <- do_this+ addToFinderCache fc mod result+ return result++-- This returns a module because it's more convenient for users+addHomeModuleToFinder :: FinderCache -> HomeUnit -> ModuleName -> ModLocation -> IO Module+addHomeModuleToFinder fc home_unit mod_name loc = do+ let mod = mkHomeInstalledModule home_unit mod_name+ addToFinderCache fc mod (InstalledFound loc mod)+ return (mkHomeModule home_unit mod_name)++uncacheModule :: FinderCache -> HomeUnit -> ModuleName -> IO ()+uncacheModule fc home_unit mod_name = do+ let mod = mkHomeInstalledModule home_unit mod_name+ removeFromFinderCache fc mod++-- -----------------------------------------------------------------------------+-- The internal workers++findHomeModule :: FinderCache -> FinderOpts -> HomeUnit -> ModuleName -> IO FindResult+findHomeModule fc fopts home_unit mod_name = do+ let uid = homeUnitAsUnit home_unit+ r <- findInstalledHomeModule fc fopts home_unit mod_name+ return $ case r of+ InstalledFound loc _ -> Found loc (mkHomeModule home_unit mod_name)+ InstalledNoPackage _ -> NoPackage uid -- impossible+ InstalledNotFound fps _ -> NotFound {+ fr_paths = fps,+ fr_pkg = Just uid,+ fr_mods_hidden = [],+ fr_pkgs_hidden = [],+ fr_unusables = [],+ fr_suggestions = []+ }++-- | Implements the search for a module name in the home package only. Calling+-- this function directly is usually *not* what you want; currently, it's used+-- as a building block for the following operations:+--+-- 1. When you do a normal package lookup, we first check if the module+-- is available in the home module, before looking it up in the package+-- database.+--+-- 2. When you have a package qualified import with package name "this",+-- we shortcut to the home module.+--+-- 3. When we look up an exact 'Module', if the unit id associated with+-- the module is the current home module do a look up in the home module.+--+-- 4. Some special-case code in GHCi (ToDo: Figure out why that needs to+-- call this.)+findInstalledHomeModule :: FinderCache -> FinderOpts -> HomeUnit -> ModuleName -> IO InstalledFindResult+findInstalledHomeModule fc fopts home_unit mod_name = do+ homeSearchCache fc home_unit mod_name $+ let+ home_path = finder_importPaths fopts+ hisuf = finder_hiSuf fopts+ mod = mkHomeInstalledModule home_unit mod_name++ source_exts =+ [ ("hs", mkHomeModLocationSearched fopts mod_name "hs")+ , ("lhs", mkHomeModLocationSearched fopts mod_name "lhs")+ , ("hsig", mkHomeModLocationSearched fopts mod_name "hsig")+ , ("lhsig", mkHomeModLocationSearched fopts mod_name "lhsig")+ ]++ -- we use mkHomeModHiOnlyLocation instead of mkHiOnlyModLocation so that+ -- when hiDir field is set in dflags, we know to look there (see #16500)+ hi_exts = [ (hisuf, mkHomeModHiOnlyLocation fopts mod_name)+ , (addBootSuffix hisuf, mkHomeModHiOnlyLocation fopts mod_name)+ ]++ -- In compilation manager modes, we look for source files in the home+ -- package because we can compile these automatically. In one-shot+ -- compilation mode we look for .hi and .hi-boot files only.+ exts | finder_lookupHomeInterfaces fopts = hi_exts+ | otherwise = source_exts+ in++ -- special case for GHC.Prim; we won't find it in the filesystem.+ -- This is important only when compiling the base package (where GHC.Prim+ -- is a home module).+ if mod `installedModuleEq` gHC_PRIM+ then return (InstalledFound (error "GHC.Prim ModLocation") mod)+ else searchPathExts home_path mod exts+++-- | Search for a module in external packages only.+findPackageModule :: FinderCache -> UnitState -> FinderOpts -> InstalledModule -> IO InstalledFindResult+findPackageModule fc unit_state fopts mod = do+ let pkg_id = moduleUnit mod+ case lookupUnitId unit_state pkg_id of+ Nothing -> return (InstalledNoPackage pkg_id)+ Just u -> findPackageModule_ fc fopts mod u++-- | Look up the interface file associated with module @mod@. This function+-- requires a few invariants to be upheld: (1) the 'Module' in question must+-- be the module identifier of the *original* implementation of a module,+-- not a reexport (this invariant is upheld by "GHC.Unit.State") and (2)+-- the 'UnitInfo' must be consistent with the unit id in the 'Module'.+-- The redundancy is to avoid an extra lookup in the package state+-- for the appropriate config.+findPackageModule_ :: FinderCache -> FinderOpts -> InstalledModule -> UnitInfo -> IO InstalledFindResult+findPackageModule_ fc fopts mod pkg_conf = do+ massertPpr (moduleUnit mod == unitId pkg_conf)+ (ppr (moduleUnit mod) <+> ppr (unitId pkg_conf))+ modLocationCache fc mod $++ -- special case for GHC.Prim; we won't find it in the filesystem.+ if mod `installedModuleEq` gHC_PRIM+ then return (InstalledFound (error "GHC.Prim ModLocation") mod)+ else++ let+ tag = waysBuildTag (finder_ways fopts)++ -- hi-suffix for packages depends on the build tag.+ package_hisuf | null tag = "hi"+ | otherwise = tag ++ "_hi"++ package_dynhisuf = waysBuildTag (addWay WayDyn (finder_ways fopts)) ++ "_hi"++ mk_hi_loc = mkHiOnlyModLocation fopts package_hisuf package_dynhisuf++ import_dirs = map ST.unpack $ unitImportDirs pkg_conf+ -- we never look for a .hi-boot file in an external package;+ -- .hi-boot files only make sense for the home package.+ in+ case import_dirs of+ [one] | finder_bypassHiFileCheck fopts ->+ -- there's only one place that this .hi file can be, so+ -- don't bother looking for it.+ let basename = moduleNameSlashes (moduleName mod)+ loc = mk_hi_loc one basename+ in return $ InstalledFound loc mod+ _otherwise ->+ searchPathExts import_dirs mod [(package_hisuf, mk_hi_loc)]++-- -----------------------------------------------------------------------------+-- General path searching++searchPathExts :: [FilePath] -- paths to search+ -> InstalledModule -- module name+ -> [ (+ FileExt, -- suffix+ FilePath -> BaseName -> ModLocation -- action+ )+ ]+ -> IO InstalledFindResult++searchPathExts paths mod exts = search to_search+ where+ basename = moduleNameSlashes (moduleName mod)++ to_search :: [(FilePath, ModLocation)]+ to_search = [ (file, fn path basename)+ | path <- paths,+ (ext,fn) <- exts,+ let base | path == "." = basename+ | otherwise = path </> basename+ file = base <.> ext+ ]++ search [] = return (InstalledNotFound (map fst to_search) (Just (moduleUnit mod)))++ search ((file, loc) : rest) = do+ b <- doesFileExist file+ if b+ then return $ InstalledFound loc mod+ else search rest++mkHomeModLocationSearched :: FinderOpts -> ModuleName -> FileExt+ -> FilePath -> BaseName -> ModLocation+mkHomeModLocationSearched fopts mod suff path basename =+ mkHomeModLocation2 fopts mod (path </> basename) suff+++-- -----------------------------------------------------------------------------+-- Constructing a home module location++-- This is where we construct the ModLocation for a module in the home+-- package, for which we have a source file. It is called from three+-- places:+--+-- (a) Here in the finder, when we are searching for a module to import,+-- using the search path (-i option).+--+-- (b) The compilation manager, when constructing the ModLocation for+-- a "root" module (a source file named explicitly on the command line+-- or in a :load command in GHCi).+--+-- (c) The driver in one-shot mode, when we need to construct a+-- ModLocation for a source file named on the command-line.+--+-- Parameters are:+--+-- mod+-- The name of the module+--+-- path+-- (a): The search path component where the source file was found.+-- (b) and (c): "."+--+-- src_basename+-- (a): (moduleNameSlashes mod)+-- (b) and (c): The filename of the source file, minus its extension+--+-- ext+-- The filename extension of the source file (usually "hs" or "lhs").++mkHomeModLocation :: FinderOpts -> ModuleName -> FilePath -> ModLocation+mkHomeModLocation dflags mod src_filename =+ let (basename,extension) = splitExtension src_filename+ in mkHomeModLocation2 dflags mod basename extension++mkHomeModLocation2 :: FinderOpts+ -> ModuleName+ -> FilePath -- Of source module, without suffix+ -> String -- Suffix+ -> ModLocation+mkHomeModLocation2 fopts mod src_basename ext =+ let mod_basename = moduleNameSlashes mod++ obj_fn = mkObjPath fopts src_basename mod_basename+ dyn_obj_fn = mkDynObjPath fopts src_basename mod_basename+ hi_fn = mkHiPath fopts src_basename mod_basename+ dyn_hi_fn = mkDynHiPath fopts src_basename mod_basename+ hie_fn = mkHiePath fopts src_basename mod_basename++ in (ModLocation{ ml_hs_file = Just (src_basename <.> ext),+ ml_hi_file = hi_fn,+ ml_dyn_hi_file = dyn_hi_fn,+ ml_obj_file = obj_fn,+ ml_dyn_obj_file = dyn_obj_fn,+ ml_hie_file = hie_fn })++mkHomeModHiOnlyLocation :: FinderOpts+ -> ModuleName+ -> FilePath+ -> BaseName+ -> ModLocation+mkHomeModHiOnlyLocation fopts mod path basename =+ let loc = mkHomeModLocation2 fopts mod (path </> basename) ""+ in loc { ml_hs_file = Nothing }++-- This function is used to make a ModLocation for a package module. Hence why+-- we explicitly pass in the interface file suffixes.+mkHiOnlyModLocation :: FinderOpts -> Suffix -> Suffix -> FilePath -> String+ -> ModLocation+mkHiOnlyModLocation fopts hisuf dynhisuf path basename+ = let full_basename = path </> basename+ obj_fn = mkObjPath fopts full_basename basename+ dyn_obj_fn = mkDynObjPath fopts full_basename basename+ hie_fn = mkHiePath fopts full_basename basename+ in ModLocation{ ml_hs_file = Nothing,+ ml_hi_file = full_basename <.> hisuf,+ -- Remove the .hi-boot suffix from+ -- hi_file, if it had one. We always+ -- want the name of the real .hi file+ -- in the ml_hi_file field.+ ml_dyn_obj_file = dyn_obj_fn,+ -- MP: TODO+ ml_dyn_hi_file = full_basename <.> dynhisuf,+ ml_obj_file = obj_fn,+ ml_hie_file = hie_fn+ }++-- | Constructs the filename of a .o file for a given source file.+-- Does /not/ check whether the .o file exists+mkObjPath+ :: FinderOpts+ -> FilePath -- the filename of the source file, minus the extension+ -> String -- the module name with dots replaced by slashes+ -> FilePath+mkObjPath fopts basename mod_basename = obj_basename <.> osuf+ where+ odir = finder_objectDir fopts+ osuf = finder_objectSuf fopts++ obj_basename | Just dir <- odir = dir </> mod_basename+ | otherwise = basename++-- | Constructs the filename of a .dyn_o file for a given source file.+-- Does /not/ check whether the .dyn_o file exists+mkDynObjPath+ :: FinderOpts+ -> FilePath -- the filename of the source file, minus the extension+ -> String -- the module name with dots replaced by slashes+ -> FilePath+mkDynObjPath fopts basename mod_basename = obj_basename <.> dynosuf+ where+ odir = finder_objectDir fopts+ dynosuf = finder_dynObjectSuf fopts++ obj_basename | Just dir <- odir = dir </> mod_basename+ | otherwise = basename+++-- | Constructs the filename of a .hi file for a given source file.+-- Does /not/ check whether the .hi file exists+mkHiPath+ :: FinderOpts+ -> FilePath -- the filename of the source file, minus the extension+ -> String -- the module name with dots replaced by slashes+ -> FilePath+mkHiPath fopts basename mod_basename = hi_basename <.> hisuf+ where+ hidir = finder_hiDir fopts+ hisuf = finder_hiSuf fopts++ hi_basename | Just dir <- hidir = dir </> mod_basename+ | otherwise = basename++-- | Constructs the filename of a .dyn_hi file for a given source file.+-- Does /not/ check whether the .dyn_hi file exists+mkDynHiPath+ :: FinderOpts+ -> FilePath -- the filename of the source file, minus the extension+ -> String -- the module name with dots replaced by slashes+ -> FilePath+mkDynHiPath fopts basename mod_basename = hi_basename <.> dynhisuf+ where+ hidir = finder_hiDir fopts+ dynhisuf = finder_dynHiSuf fopts++ hi_basename | Just dir <- hidir = dir </> mod_basename+ | otherwise = basename++-- | Constructs the filename of a .hie file for a given source file.+-- Does /not/ check whether the .hie file exists+mkHiePath+ :: FinderOpts+ -> FilePath -- the filename of the source file, minus the extension+ -> String -- the module name with dots replaced by slashes+ -> FilePath+mkHiePath fopts basename mod_basename = hie_basename <.> hiesuf+ where+ hiedir = finder_hieDir fopts+ hiesuf = finder_hieSuf fopts++ hie_basename | Just dir <- hiedir = dir </> mod_basename+ | otherwise = basename++++-- -----------------------------------------------------------------------------+-- Filenames of the stub files++-- We don't have to store these in ModLocations, because they can be derived+-- from other available information, and they're only rarely needed.++mkStubPaths+ :: FinderOpts+ -> ModuleName+ -> ModLocation+ -> FilePath++mkStubPaths fopts mod location+ = let+ stubdir = finder_stubDir fopts++ mod_basename = moduleNameSlashes mod+ src_basename = dropExtension $ expectJust "mkStubPaths"+ (ml_hs_file location)++ stub_basename0+ | Just dir <- stubdir = dir </> mod_basename+ | otherwise = src_basename++ stub_basename = stub_basename0 ++ "_stub"+ in+ stub_basename <.> "h"++-- -----------------------------------------------------------------------------+-- findLinkable isn't related to the other stuff in here,+-- but there's no other obvious place for it++findObjectLinkableMaybe :: Module -> ModLocation -> IO (Maybe Linkable)+findObjectLinkableMaybe mod locn+ = do let obj_fn = ml_obj_file locn+ maybe_obj_time <- modificationTimeIfExists obj_fn+ case maybe_obj_time of+ Nothing -> return Nothing+ Just obj_time -> liftM Just (findObjectLinkable mod obj_fn obj_time)++-- Make an object linkable when we know the object file exists, and we know+-- its modification time.+findObjectLinkable :: Module -> FilePath -> UTCTime -> IO Linkable+findObjectLinkable mod obj_fn obj_time = return (LM obj_time mod [DotO obj_fn])+ -- We used to look for _stub.o files here, but that was a bug (#706)+ -- Now GHC merges the stub.o into the main .o (#3687)+
ghc-lib.cabal view
@@ -1,7 +1,7 @@ cabal-version: >=1.22 build-type: Simple name: ghc-lib-version: 0.20211001+version: 0.20211101 license: BSD3 license-file: LICENSE category: Development@@ -64,24 +64,24 @@ else build-depends: Win32 build-depends:- ghc-prim > 0.2 && < 0.8, base >= 4.14 && < 4.17,+ ghc-prim > 0.2 && < 0.9,+ bytestring >= 0.9 && < 0.12,+ time >= 1.4 && < 1.12,+ exceptions == 0.10.*,+ parsec, containers >= 0.5 && < 0.7,- bytestring >= 0.9 && < 0.11, binary == 0.8.*, filepath >= 1 && < 1.5, directory >= 1 && < 1.4, array >= 0.1 && < 0.6, deepseq >= 1.4 && < 1.5, pretty == 1.1.*,- time >= 1.4 && < 1.10, transformers == 0.5.*, process >= 1 && < 1.7,- exceptions == 0.10.*,- parsec, rts, hpc == 0.6.*,- ghc-lib-parser == 0.20211001,+ ghc-lib-parser == 0.20211101, stm build-tools: alex >= 3.1, happy >= 1.19.4 other-extensions:@@ -223,7 +223,6 @@ GHC.Driver.CmdLine, GHC.Driver.Config, GHC.Driver.Config.Diagnostic,- GHC.Driver.Config.Finder, GHC.Driver.Config.Logger, GHC.Driver.Config.Parser, GHC.Driver.Env,@@ -340,6 +339,7 @@ GHC.Types.Annotations, GHC.Types.Avail, GHC.Types.Basic,+ GHC.Types.BreakInfo, GHC.Types.CompleteMatch, GHC.Types.CostCentre, GHC.Types.CostCentre.State,@@ -367,6 +367,7 @@ GHC.Types.Name.Ppr, GHC.Types.Name.Reader, GHC.Types.Name.Set,+ GHC.Types.PkgQual, GHC.Types.RepType, GHC.Types.SafeHaskell, GHC.Types.SourceError,@@ -393,7 +394,6 @@ GHC.Unit.Database, GHC.Unit.Env, GHC.Unit.External,- GHC.Unit.Finder, GHC.Unit.Finder.Types, GHC.Unit.Home, GHC.Unit.Home.ModInfo,@@ -616,6 +616,7 @@ GHC.Driver.Backpack GHC.Driver.CodeOutput GHC.Driver.Config.CmmToAsm+ GHC.Driver.Config.Finder GHC.Driver.GenerateCgIPEStub GHC.Driver.Main GHC.Driver.Make@@ -779,6 +780,7 @@ GHC.Tc.TyCl.Utils GHC.Tc.Types.EvTerm GHC.Tc.Utils.Backpack+ GHC.Tc.Utils.Concrete GHC.Tc.Utils.Env GHC.Tc.Utils.Instantiate GHC.Tc.Utils.Monad@@ -789,6 +791,7 @@ GHC.ThToHs GHC.Types.Name.Shape GHC.Types.TyThing.Ppr+ GHC.Unit.Finder GHC.Utils.Asm GHC.Utils.Monad.State.Lazy GHCi.CreateBCO
ghc-lib/stage0/lib/ghcautoconf.h view
@@ -97,7 +97,7 @@ /* Define to 1 if you have the <bfd.h> header file. */ /* #undef HAVE_BFD_H */ -/* Does GCC support __atomic primitives? */+/* Does C compiler support __atomic primitives? */ #define HAVE_C11_ATOMICS 1 /* Define to 1 if you have the `clock_gettime' function. */@@ -377,6 +377,9 @@ /* Define to 1 if C symbols have a leading underscore added by the compiler. */ #define LEADING_UNDERSCORE 1++/* Define to 1 if we need -latomic for sub-word atomic operations. */+#define NEED_ATOMIC_LIB 0 /* Define 1 if we need to link code using pthreads with -lpthread */ #define NEED_PTHREAD_LIB 0